Compare commits
328 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
533db98c6f | ||
|
|
8039f1b2a0 | ||
|
|
4280563b04 | ||
|
|
3e88e97c11 | ||
|
|
f134b3993a | ||
|
|
fceb0f80bc | ||
|
|
e0c99c4ea1 | ||
|
|
a5297ece62 | ||
|
|
254114616a | ||
|
|
33999c4317 | ||
|
|
5f232d72d4 | ||
|
|
313332d111 | ||
|
|
f99c9feaf7 | ||
|
|
8ac25e5201 | ||
|
|
f9e1b16098 | ||
|
|
4845e16c22 | ||
|
|
553a175c90 | ||
|
|
740a4f7a02 | ||
|
|
44c4693539 | ||
|
|
dc9b74647e | ||
|
|
b59f186011 | ||
|
|
e5f275e72a | ||
|
|
1cdf6b9590 | ||
|
|
ee0855f427 | ||
|
|
7e4c258e16 | ||
|
|
07276b8682 | ||
|
|
ea5f065745 | ||
|
|
2d40460cf7 | ||
|
|
254dc4d9f3 | ||
|
|
42a57ea802 | ||
|
|
04bf10e6a9 | ||
|
|
c61e75b76d | ||
|
|
7c908bcf4e | ||
|
|
a8e503dce0 | ||
|
|
45463ab3ac | ||
|
|
febc09b480 | ||
|
|
4a9df08157 | ||
|
|
da996a15be | ||
|
|
6b1a2c1d81 | ||
|
|
de4aad5ba6 | ||
|
|
156f0eca20 | ||
|
|
4f080e498c | ||
|
|
fe8c10695c | ||
|
|
daee08562c | ||
|
|
ab693a926f | ||
|
|
607615f4f6 | ||
|
|
e1e740717b | ||
|
|
ac799e569d | ||
|
|
0962f684a0 | ||
|
|
b888986054 | ||
|
|
addce2f9f2 | ||
|
|
74bcf3d0d2 | ||
|
|
b630219b13 | ||
|
|
7943da1e81 | ||
|
|
e3c06424ae | ||
|
|
5f4c5c920f | ||
|
|
112224d8d2 | ||
|
|
87d7e4c55b | ||
|
|
3bcf8c23de | ||
|
|
a4f9bd586b | ||
|
|
ff8f6f21f7 | ||
|
|
19176e3c08 | ||
|
|
d16c26da40 | ||
|
|
a8c155cab9 | ||
|
|
995410463a | ||
|
|
208905257f | ||
|
|
891a6332e3 | ||
|
|
a4842c92ea | ||
|
|
ada8bbbd6a | ||
|
|
e9c3b27b4b | ||
|
|
b0446ff06a | ||
|
|
db7dfe0550 | ||
|
|
646835fb59 | ||
|
|
c2a1961747 | ||
|
|
6584a6eec4 | ||
|
|
86d5ac0882 | ||
|
|
476f53879e | ||
|
|
c69a5fc53a | ||
|
|
a35aaf704c | ||
|
|
3c3696d554 | ||
|
|
90b511ec7a | ||
|
|
02372952e4 | ||
|
|
9fde224a53 | ||
|
|
ca02c4bb40 | ||
|
|
c37d89827e | ||
|
|
6c6699f3d2 | ||
|
|
9320a0139d | ||
|
|
fbcda19a23 | ||
|
|
cd28a946d5 | ||
|
|
8243f3f063 | ||
|
|
df31952275 | ||
|
|
1a191701fe | ||
|
|
99563e9173 | ||
|
|
17d274dc12 | ||
|
|
6b5d9fd316 | ||
|
|
2c560374d6 | ||
|
|
2e385738a4 | ||
|
|
c4a3b92e09 | ||
|
|
6daef4e7c8 | ||
|
|
3e956805e8 | ||
|
|
1b6e3dd985 | ||
|
|
5398b71158 | ||
|
|
f3c956006a | ||
|
|
4eba294c69 | ||
|
|
5200721e5c | ||
|
|
e9d80d939e | ||
|
|
ef1103d3e9 | ||
|
|
67338703aa | ||
|
|
7939d92fcc | ||
|
|
d92e5713be | ||
|
|
93b61fc4ec | ||
|
|
77987e5ee3 | ||
|
|
0df46f01a9 | ||
|
|
f457d0b4c6 | ||
|
|
1c79cb82ab | ||
|
|
89a46a57df | ||
|
|
eb53139ee5 | ||
|
|
38a7600920 | ||
|
|
ed1264f077 | ||
|
|
ef06b54f8d | ||
|
|
1b77c3d7b9 | ||
|
|
5ccfcd17ff | ||
|
|
a8ab2bcb62 | ||
|
|
8646349aeb | ||
|
|
f31779a112 | ||
|
|
0e2402eb20 | ||
|
|
f695f95290 | ||
|
|
5de83dcc0f | ||
|
|
5135f98795 | ||
|
|
26bca0005c | ||
|
|
e0e98d9560 | ||
|
|
4ab827b869 | ||
|
|
3456b6634a | ||
|
|
75c979847f | ||
|
|
6aa8254bb7 | ||
|
|
ca8f91f6f6 | ||
|
|
2398554c60 | ||
|
|
0ca3deebcf | ||
|
|
99e1024051 | ||
|
|
696950aa69 | ||
|
|
a8c2bbdabf | ||
|
|
50ab2dde94 | ||
|
|
d331ba0411 | ||
|
|
00aa0043c7 | ||
|
|
cc680065c3 | ||
|
|
f9d78089c6 | ||
|
|
562f17efab | ||
|
|
9e9b54d7f6 | ||
|
|
029e8bd618 | ||
|
|
e81fcfe3f2 | ||
|
|
aac177c484 | ||
|
|
6b1ae49571 | ||
|
|
e03ac20f94 | ||
|
|
e9252bcdcc | ||
|
|
e0fe347967 | ||
|
|
d48c69246c | ||
|
|
443b7ff2a8 | ||
|
|
d4e24b349e | ||
|
|
bdce84a539 | ||
|
|
a1f157e9a9 | ||
|
|
605a880c8c | ||
|
|
2980f27779 | ||
|
|
eda36a1c75 | ||
|
|
ca12911d1f | ||
|
|
d55cc79bcf | ||
|
|
11ca4f6b69 | ||
|
|
56c7d1070a | ||
|
|
7e2ea902f8 | ||
|
|
3607f4838a | ||
|
|
5eb20b3007 | ||
|
|
4c9392b43e | ||
|
|
227e8414cc | ||
|
|
2df9622477 | ||
|
|
ebc22ef7e1 | ||
|
|
92e65ca68f | ||
|
|
403d4fb852 | ||
|
|
2e4db3344f | ||
|
|
d42a90cf4f | ||
|
|
58def9f2e6 | ||
|
|
dd9974bbb8 | ||
|
|
22e39ea72e | ||
|
|
2567726503 | ||
|
|
9dd378ff12 | ||
|
|
ad03c48a71 | ||
|
|
9b042f9d59 | ||
|
|
27ba5e8b1f | ||
|
|
662957cc73 | ||
|
|
88479c6fc3 | ||
|
|
70f1d766e8 | ||
|
|
885532c124 | ||
|
|
5f31228d7d | ||
|
|
fcb4e0f137 | ||
|
|
a84862dbdc | ||
|
|
86b1913474 | ||
|
|
a9575dcf62 | ||
|
|
19cc5af41e | ||
|
|
498514c04d | ||
|
|
a92acdb188 | ||
|
|
d99f8bba2e | ||
|
|
8a7b487e3b | ||
|
|
4632e36a4e | ||
|
|
eb1f77dedf | ||
|
|
be91130f18 | ||
|
|
5adf40208f | ||
|
|
037b25cfdc | ||
|
|
0d9834caeb | ||
|
|
e670e72fa0 | ||
|
|
a53da6abe1 | ||
|
|
32b0cad8f7 | ||
|
|
ed8b68dd17 | ||
|
|
c6a7e18636 | ||
|
|
cbbe8666a8 | ||
|
|
e0131f1eda | ||
|
|
5a78dd7cfe | ||
|
|
d814852baf | ||
|
|
f83903bfcc | ||
|
|
192555bb0e | ||
|
|
a69b80d07e | ||
|
|
2c5fd26c07 | ||
|
|
0461c0d8a4 | ||
|
|
899e3d1297 | ||
|
|
0a7dc1b1c7 | ||
|
|
cd90a4d8c0 | ||
|
|
3dd2c62770 | ||
|
|
93b58361d9 | ||
|
|
594ea533d3 | ||
|
|
062fb31155 | ||
|
|
7588b6b291 | ||
|
|
569c3b28ee | ||
|
|
bc78de3a52 | ||
|
|
989b0cccc2 | ||
|
|
76e44c2911 | ||
|
|
8759c5c8d6 | ||
|
|
44c3d3d665 | ||
|
|
ae3190c5e9 | ||
|
|
a0fdb63060 | ||
|
|
b48e739998 | ||
|
|
ff6283340a | ||
|
|
d85cf3e5ab | ||
|
|
32b411496b | ||
|
|
0605cd9f38 | ||
|
|
8bda71558c | ||
|
|
f82c662b8d | ||
|
|
0a82580bfc | ||
|
|
442150e0e2 | ||
|
|
10a4c88f58 | ||
|
|
a4b2d0d518 | ||
|
|
1f0b03ced0 | ||
|
|
152bfe3769 | ||
|
|
19ca800caa | ||
|
|
a657bc5dee | ||
|
|
9ff42a8798 | ||
|
|
87c03a0a13 | ||
|
|
221f3002ca | ||
|
|
55b54b0d63 | ||
|
|
4b3728f05e | ||
|
|
f02ba2fcc5 | ||
|
|
14f7c07271 | ||
|
|
2fe5b572bc | ||
|
|
bb9a24d9fc | ||
|
|
b2357ecd82 | ||
|
|
c492f97541 | ||
|
|
37906d4dfb | ||
|
|
d676c047b1 | ||
|
|
ddc26c9db1 | ||
|
|
dc44bca85b | ||
|
|
9eabb37338 | ||
|
|
a6ce56d9a9 | ||
|
|
5269823927 | ||
|
|
0f8a1e02ff | ||
|
|
b65afdd0c1 | ||
|
|
de1eaa2655 | ||
|
|
ae9017ceab | ||
|
|
a0b91fbd65 | ||
|
|
b83090fca2 | ||
|
|
deba48a727 | ||
|
|
b6b33bfb92 | ||
|
|
7c864c9834 | ||
|
|
19557443c8 | ||
|
|
e5a2062c80 | ||
|
|
9b62ee71f4 | ||
|
|
5f05181a8b | ||
|
|
b000019578 | ||
|
|
028c8e6cf5 | ||
|
|
18eaf51bd5 | ||
|
|
829401dc17 | ||
|
|
fd2d279984 | ||
|
|
b25bcd460f | ||
|
|
77656c557a | ||
|
|
7f3826e8e4 | ||
|
|
313c8c55de | ||
|
|
d46b04a27d | ||
|
|
5f38ef6719 | ||
|
|
61e713c1d3 | ||
|
|
1185f88d35 | ||
|
|
91add7bbdc | ||
|
|
5a274a37e0 | ||
|
|
60c797e744 | ||
|
|
af4987e19f | ||
|
|
35dcf02b04 | ||
|
|
e5fdd994bf | ||
|
|
4749dcb7c5 | ||
|
|
5b51a2b9e2 | ||
|
|
6093f1862a | ||
|
|
89dbd487fc | ||
|
|
87276ef1ef | ||
|
|
f13abbbb44 | ||
|
|
43d18bc2d3 | ||
|
|
b158439a5b | ||
|
|
059760548f | ||
|
|
886c5ad936 | ||
|
|
f0edf41e3e | ||
|
|
f9f17f6c8d | ||
|
|
453f505256 | ||
|
|
b3a95caf61 | ||
|
|
6099351c76 | ||
|
|
af8532f251 | ||
|
|
cabd8a0e70 | ||
|
|
540efebcc3 | ||
|
|
0bf1f39ec6 | ||
|
|
056073de4c | ||
|
|
d2a1b8854d | ||
|
|
f2813ee33d | ||
|
|
d634548243 | ||
|
|
54cfa95d3a | ||
|
|
d5f3c50f58 | ||
|
|
79dcc47191 | ||
|
|
d16fe4be5b |
34
.eslintrc.js
34
.eslintrc.js
@@ -446,10 +446,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'scripts/eslint-rules/*.js',
|
||||
'packages/eslint-plugin-react-hooks/src/*.js',
|
||||
],
|
||||
files: ['scripts/eslint-rules/*.js'],
|
||||
plugins: ['eslint-plugin'],
|
||||
rules: {
|
||||
'eslint-plugin/prefer-object-rule': ERROR,
|
||||
@@ -496,9 +493,11 @@ module.exports = {
|
||||
{
|
||||
files: [
|
||||
'packages/react-devtools-extensions/**/*.js',
|
||||
'packages/react-devtools-shared/src/devtools/views/**/*.js',
|
||||
'packages/react-devtools-shared/src/hook.js',
|
||||
'packages/react-devtools-shared/src/backend/console.js',
|
||||
'packages/react-devtools-shared/src/backend/shared/DevToolsComponentStackFrame.js',
|
||||
'packages/react-devtools-shared/src/frontend/utils/withPermissionsCheck.js',
|
||||
],
|
||||
globals: {
|
||||
__IS_CHROME__: 'readonly',
|
||||
@@ -506,6 +505,7 @@ module.exports = {
|
||||
__IS_EDGE__: 'readonly',
|
||||
__IS_NATIVE__: 'readonly',
|
||||
__IS_INTERNAL_VERSION__: 'readonly',
|
||||
chrome: 'readonly',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -514,6 +514,26 @@ module.exports = {
|
||||
__IS_INTERNAL_VERSION__: 'readonly',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['packages/eslint-plugin-react-hooks/src/**/*'],
|
||||
extends: ['plugin:@typescript-eslint/recommended'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint', 'eslint-plugin'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': OFF,
|
||||
'@typescript-eslint/no-non-null-assertion': OFF,
|
||||
'@typescript-eslint/array-type': [ERROR, {default: 'generic'}],
|
||||
|
||||
'es/no-optional-chaining': OFF,
|
||||
|
||||
'eslint-plugin/prefer-object-rule': ERROR,
|
||||
'eslint-plugin/require-meta-fixable': [
|
||||
ERROR,
|
||||
{catchNoFixerButFixableProperty: true},
|
||||
],
|
||||
'eslint-plugin/require-meta-has-suggestions': ERROR,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
env: {
|
||||
@@ -589,6 +609,12 @@ module.exports = {
|
||||
WheelEventHandler: 'readonly',
|
||||
FinalizationRegistry: 'readonly',
|
||||
Omit: 'readonly',
|
||||
Keyframe: 'readonly',
|
||||
PropertyIndexedKeyframes: 'readonly',
|
||||
KeyframeAnimationOptions: 'readonly',
|
||||
GetAnimationsOptions: 'readonly',
|
||||
Animatable: 'readonly',
|
||||
ScrollTimeline: 'readonly',
|
||||
|
||||
spyOnDev: 'readonly',
|
||||
spyOnDevAndProd: 'readonly',
|
||||
|
||||
35
.github/workflows/compiler_discord_notify.yml
vendored
Normal file
35
.github/workflows/compiler_discord_notify.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: (Compiler) Discord Notify
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, ready_for_review]
|
||||
paths:
|
||||
- compiler/**
|
||||
- .github/workflows/compiler_**.yml
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
check_maintainer:
|
||||
uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
|
||||
permissions:
|
||||
# Used by check_maintainer
|
||||
contents: read
|
||||
with:
|
||||
actor: ${{ github.event.pull_request.user.login }}
|
||||
|
||||
notify:
|
||||
if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }}
|
||||
needs: check_maintainer
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Discord Webhook Action
|
||||
uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
|
||||
with:
|
||||
webhook-url: ${{ secrets.COMPILER_DISCORD_WEBHOOK_URL }}
|
||||
embed-author-name: ${{ github.event.pull_request.user.login }}
|
||||
embed-author-url: ${{ github.event.pull_request.user.html_url }}
|
||||
embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }}
|
||||
embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}'
|
||||
embed-description: ${{ github.event.pull_request.body }}
|
||||
embed-url: ${{ github.event.pull_request.html_url }}
|
||||
24
.github/workflows/compiler_playground.yml
vendored
24
.github/workflows/compiler_playground.yml
vendored
@@ -8,6 +8,8 @@ on:
|
||||
- compiler/**
|
||||
- .github/workflows/compiler_playground.yml
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
@@ -36,10 +38,27 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-and-playground-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
working-directory: compiler
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Check Playwright version
|
||||
id: playwright_version
|
||||
run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT"
|
||||
- name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }}
|
||||
id: cache_playwright_browsers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }}
|
||||
- run: npx playwright install --with-deps chromium
|
||||
if: steps.cache_playwright_browsers.outputs.cache-hit != 'true'
|
||||
- run: npx playwright install-deps
|
||||
if: steps.cache_playwright_browsers.outputs.cache-hit == 'true'
|
||||
- run: CI=true yarn test
|
||||
- run: ls -R test-results
|
||||
if: '!cancelled()'
|
||||
@@ -49,3 +68,4 @@ jobs:
|
||||
with:
|
||||
name: test-results
|
||||
path: compiler/apps/playground/test-results
|
||||
if-no-files-found: ignore
|
||||
|
||||
9
.github/workflows/compiler_prereleases.yml
vendored
9
.github/workflows/compiler_prereleases.yml
vendored
@@ -20,11 +20,12 @@ on:
|
||||
NPM_TOKEN:
|
||||
required: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
defaults:
|
||||
@@ -46,9 +47,11 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Publish packages to npm
|
||||
run: |
|
||||
cp ./scripts/release/ci-npmrc ~/.npmrc
|
||||
|
||||
@@ -15,6 +15,8 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ on:
|
||||
# At 10 minutes past 16:00 on Mon, Tue, Wed, Thu, and Fri
|
||||
- cron: 10 16 * * 1,2,3,4,5
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ on:
|
||||
# At 10 minutes past 9:00 on Mon
|
||||
- cron: 10 9 * * 1
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
|
||||
77
.github/workflows/compiler_rust.yml
vendored
77
.github/workflows/compiler_rust.yml
vendored
@@ -1,77 +0,0 @@
|
||||
name: (Compiler) Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
paths:
|
||||
- .github/workflows/**
|
||||
- compiler/crates/**
|
||||
- compiler/Cargo.*
|
||||
- compiler/*.toml
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/**
|
||||
- compiler/crates/**
|
||||
- compiler/Cargo.*
|
||||
- compiler/*.toml
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTFLAGS: -Dwarnings
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: compiler
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Rust Test (${{ matrix.target.os }})
|
||||
strategy:
|
||||
matrix:
|
||||
target:
|
||||
- target: ubuntu-latest
|
||||
os: ubuntu-latest
|
||||
# TODO: run on more platforms
|
||||
# - target: macos-latest
|
||||
# os: macos-latest
|
||||
# - target: windows-latest
|
||||
# os: windows-latest
|
||||
runs-on: ${{ matrix.target.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: cargo test
|
||||
run: cargo test --manifest-path=Cargo.toml --locked ${{ matrix.target.features && '--features' }} ${{ matrix.target.features }}
|
||||
|
||||
lint:
|
||||
name: Rust Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
# NOTE: use `rustup run <toolchain> <command>` in commands below
|
||||
# with this exact same toolchain value
|
||||
toolchain: nightly-2023-08-01
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: rustfmt
|
||||
run: grep -r --include "*.rs" --files-without-match "@generated" crates | xargs rustup run nightly-2023-08-01 rustfmt --check --config="skip_children=true"
|
||||
# - name: cargo clippy
|
||||
# run: rustup run nightly-2023-08-01 cargo clippy -- -Dclippy::correctness
|
||||
|
||||
build:
|
||||
name: Rust Build
|
||||
runs-on: ubuntu-latest
|
||||
# TODO: build on more platforms, deploy, etc
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: cargo build
|
||||
run: cargo build --release
|
||||
26
.github/workflows/compiler_typescript.yml
vendored
26
.github/workflows/compiler_typescript.yml
vendored
@@ -8,6 +8,8 @@ on:
|
||||
- compiler/**
|
||||
- .github/workflows/compiler_typescript.yml
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
@@ -45,10 +47,13 @@ jobs:
|
||||
cache-dependency-path: compiler/yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn workspace babel-plugin-react-compiler lint
|
||||
|
||||
# Hardcoded to improve parallelism
|
||||
@@ -66,17 +71,19 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn workspace babel-plugin-react-compiler jest
|
||||
|
||||
test:
|
||||
name: Test ${{ matrix.workspace_name }}
|
||||
needs: discover_yarn_workspaces
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
workspace_name: ${{ fromJSON(needs.discover_yarn_workspaces.outputs.matrix) }}
|
||||
steps:
|
||||
@@ -90,7 +97,12 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: xvfb-run -a yarn workspace ${{ matrix.workspace_name }} test
|
||||
if: runner.os == 'Linux' && matrix.workspace_name == 'react-forgive'
|
||||
- run: yarn workspace ${{ matrix.workspace_name }} test
|
||||
if: matrix.workspace_name != 'react-forgive'
|
||||
|
||||
59
.github/workflows/devtools_regression_tests.yml
vendored
59
.github/workflows/devtools_regression_tests.yml
vendored
@@ -9,6 +9,8 @@ on:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
|
||||
@@ -18,6 +20,9 @@ jobs:
|
||||
download_build:
|
||||
name: Download base build
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
|
||||
actions: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@@ -29,13 +34,15 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Download react-devtools artifacts for base revision
|
||||
run: |
|
||||
git fetch origin main
|
||||
@@ -47,6 +54,7 @@ jobs:
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
if-no-files-found: error
|
||||
|
||||
build_devtools_and_process_artifacts:
|
||||
name: Build DevTools and process artifacts
|
||||
@@ -63,11 +71,13 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -83,23 +93,27 @@ jobs:
|
||||
with:
|
||||
name: react-devtools
|
||||
path: build/devtools.tgz
|
||||
if-no-files-found: error
|
||||
# Simplifies getting the extension for local testing
|
||||
- name: Archive chrome extension
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: react-devtools-chrome-extension
|
||||
path: build/devtools/chrome-extension.zip
|
||||
if-no-files-found: error
|
||||
- name: Archive firefox extension
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: react-devtools-firefox-extension
|
||||
path: build/devtools/firefox-extension.zip
|
||||
if-no-files-found: error
|
||||
|
||||
run_devtools_tests_for_versions:
|
||||
name: Run DevTools tests for versions
|
||||
needs: build_devtools_and_process_artifacts
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version:
|
||||
- "16.0"
|
||||
@@ -108,7 +122,6 @@ jobs:
|
||||
- "17.0"
|
||||
- "18.0"
|
||||
- "18.2" # compiler polyfill
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@@ -120,9 +133,11 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore all archived build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
- name: Display structure of build
|
||||
@@ -135,6 +150,7 @@ jobs:
|
||||
needs: build_devtools_and_process_artifacts
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version:
|
||||
- "16.0"
|
||||
@@ -142,7 +158,6 @@ jobs:
|
||||
- "16.8" # hooks
|
||||
- "17.0"
|
||||
- "18.0"
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@@ -154,17 +169,28 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore all archived build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- name: Playwright install deps
|
||||
run: |
|
||||
npx playwright install
|
||||
sudo npx playwright install-deps
|
||||
- name: Check Playwright version
|
||||
id: playwright_version
|
||||
run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT"
|
||||
- name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }}
|
||||
id: cache_playwright_browsers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }}
|
||||
- run: npx playwright install --with-deps
|
||||
if: steps.cache_playwright_browsers.outputs.cache-hit != 'true'
|
||||
- run: npx playwright install-deps
|
||||
if: steps.cache_playwright_browsers.outputs.cache-hit == 'true'
|
||||
- run: ./scripts/ci/download_devtools_regression_build.js ${{ matrix.version }}
|
||||
- run: ls -R build-regression
|
||||
- run: ./scripts/ci/run_devtools_e2e_tests.js ${{ matrix.version }}
|
||||
@@ -176,3 +202,4 @@ jobs:
|
||||
with:
|
||||
name: screenshots
|
||||
path: ./tmp/screenshots
|
||||
if-no-files-found: warn
|
||||
|
||||
459
.github/workflows/runtime_build_and_test.yml
vendored
459
.github/workflows/runtime_build_and_test.yml
vendored
@@ -7,6 +7,8 @@ on:
|
||||
paths-ignore:
|
||||
- compiler/**
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
@@ -17,6 +19,95 @@ env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
|
||||
|
||||
jobs:
|
||||
# ----- NODE_MODULES CACHE -----
|
||||
# Centralize the node_modules cache so it is saved once and each subsequent job only needs to
|
||||
# restore the cache. Prevents race conditions where multiple workflows try to write to the cache.
|
||||
runtime_node_modules_cache:
|
||||
name: Cache Runtime node_modules
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
- name: Check cache hit
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
lookup-only: true
|
||||
- uses: actions/setup-node@v4
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Warm with old cache
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-node_modules-v6-
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Save cache
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
|
||||
runtime_compiler_node_modules_cache:
|
||||
name: Cache Runtime, Compiler node_modules
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
- name: Check cache hit
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
lookup-only: true
|
||||
- uses: actions/setup-node@v4
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
- name: Warm with old cache
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-and-compiler-node_modules-v6-
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Save cache
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
|
||||
# ----- FLOW -----
|
||||
discover_flow_inline_configs:
|
||||
name: Discover flow inline configs
|
||||
@@ -36,10 +127,10 @@ jobs:
|
||||
|
||||
flow:
|
||||
name: Flow check ${{ matrix.flow_inline_config_shortname }}
|
||||
needs: discover_flow_inline_configs
|
||||
needs: [discover_flow_inline_configs, runtime_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
flow_inline_config_shortname: ${{ fromJSON(needs.discover_flow_inline_configs.outputs.matrix) }}
|
||||
steps:
|
||||
@@ -52,19 +143,25 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: node ./scripts/tasks/flow-ci ${{ matrix.flow_inline_config_shortname }}
|
||||
|
||||
# ----- FIZZ -----
|
||||
check_generated_fizz_runtime:
|
||||
name: Confirm generated inline Fizz runtime is up to date
|
||||
needs: [runtime_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -76,14 +173,19 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: |
|
||||
yarn generate-inline-fizz-runtime
|
||||
git diff --quiet || (echo "There was a change to the Fizz runtime. Run `yarn generate-inline-fizz-runtime` and check in the result." && false)
|
||||
@@ -91,6 +193,7 @@ jobs:
|
||||
# ----- FEATURE FLAGS -----
|
||||
flags:
|
||||
name: Check flags
|
||||
needs: [runtime_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -102,21 +205,25 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn flags
|
||||
|
||||
# ----- TESTS -----
|
||||
test:
|
||||
name: yarn test ${{ matrix.params }} (Shard ${{ matrix.shard }})
|
||||
needs: [runtime_compiler_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
params:
|
||||
- "-r=stable --env=development"
|
||||
@@ -144,7 +251,6 @@ jobs:
|
||||
- 3/5
|
||||
- 4/5
|
||||
- 5/5
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -153,26 +259,37 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-and-compiler-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }}
|
||||
|
||||
# ----- BUILD -----
|
||||
build_and_lint:
|
||||
name: yarn build and lint
|
||||
needs: [runtime_compiler_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# yml is dumb. update the --total arg to yarn build if you change the number of workers
|
||||
worker_id: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
|
||||
worker_id: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
|
||||
release_channel: [stable, experimental]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -182,21 +299,30 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11.0.22
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-and-compiler-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn build --index=${{ matrix.worker_id }} --total=20 --r=${{ matrix.release_channel }} --ci
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn build --index=${{ matrix.worker_id }} --total=25 --r=${{ matrix.release_channel }} --ci
|
||||
env:
|
||||
CI: github
|
||||
RELEASE_CHANNEL: ${{ matrix.release_channel }}
|
||||
@@ -210,11 +336,13 @@ jobs:
|
||||
with:
|
||||
name: _build_${{ matrix.worker_id }}_${{ matrix.release_channel }}
|
||||
path: build
|
||||
if-no-files-found: error
|
||||
|
||||
test_build:
|
||||
name: yarn test-build
|
||||
needs: build_and_lint
|
||||
needs: [build_and_lint, runtime_compiler_node_modules_cache]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test_params: [
|
||||
# Intentionally passing these as strings instead of creating a
|
||||
@@ -247,10 +375,16 @@ jobs:
|
||||
# TODO: Test more persistent configurations?
|
||||
]
|
||||
shard:
|
||||
- 1/3
|
||||
- 2/3
|
||||
- 3/3
|
||||
continue-on-error: true
|
||||
- 1/10
|
||||
- 2/10
|
||||
- 3/10
|
||||
- 4/10
|
||||
- 5/10
|
||||
- 6/10
|
||||
- 7/10
|
||||
- 8/10
|
||||
- 9/10
|
||||
- 10/10
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -260,16 +394,25 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-and-compiler-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -282,7 +425,11 @@ jobs:
|
||||
|
||||
process_artifacts_combined:
|
||||
name: Process artifacts combined
|
||||
needs: build_and_lint
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
permissions:
|
||||
# https://github.com/actions/attest-build-provenance
|
||||
id-token: write
|
||||
attestations: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -294,14 +441,19 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -310,7 +462,7 @@ jobs:
|
||||
merge-multiple: true
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- run: echo ${{ github.sha }} >> build/COMMIT_SHA
|
||||
- run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA
|
||||
- name: Scrape warning messages
|
||||
run: |
|
||||
mkdir -p ./build/__test_utils__
|
||||
@@ -320,16 +472,29 @@ jobs:
|
||||
# TODO: Migrate scripts to use `build` directory instead of `build2`
|
||||
- run: cp ./build.tgz ./build2.tgz
|
||||
- name: Archive build artifacts
|
||||
id: upload_artifacts_combined
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifacts_combined
|
||||
path: |
|
||||
./build.tgz
|
||||
./build2.tgz
|
||||
if-no-files-found: error
|
||||
- uses: actions/attest-build-provenance@v2
|
||||
# We don't verify builds generated from pull requests not originating from facebook/react.
|
||||
# However, if the PR lands, the run on `main` will generate the attestation which can then
|
||||
# be used to download a build via scripts/release/download-experimental-build.js.
|
||||
#
|
||||
# Note that this means that scripts/release/download-experimental-build.js must be run with
|
||||
# --no-verify when downloading a build from a fork.
|
||||
if: github.event_name == 'push' && github.ref_name == 'main' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
with:
|
||||
subject-name: artifacts_combined.zip
|
||||
subject-digest: sha256:${{ steps.upload_artifacts_combined.outputs.artifact-digest }}
|
||||
|
||||
check_error_codes:
|
||||
name: Search build artifacts for unminified errors
|
||||
needs: build_and_lint
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -341,14 +506,19 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -364,7 +534,7 @@ jobs:
|
||||
|
||||
check_release_dependencies:
|
||||
name: Check release dependencies
|
||||
needs: build_and_lint
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -376,14 +546,19 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -408,16 +583,16 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: fixtures_dom-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: fixtures_dom-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'fixtures/dom/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
|
||||
working-directory: fixtures/dom
|
||||
- run: yarn --cwd fixtures/dom install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -452,14 +627,31 @@ jobs:
|
||||
# That means dependencies of the built packages are not installed.
|
||||
# We need to install dependencies of the workroot to fulfill all dependency constraints
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: fixtures_flight-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: fixtures_flight-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'fixtures/flight/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd fixtures/flight install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Check Playwright version
|
||||
id: playwright_version
|
||||
run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT"
|
||||
- name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }}
|
||||
id: cache_playwright_browsers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }}
|
||||
- name: Playwright install deps
|
||||
if: steps.cache_playwright_browsers.outputs.cache-hit != 'true'
|
||||
working-directory: fixtures/flight
|
||||
run: npx playwright install --with-deps chromium
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -468,18 +660,6 @@ jobs:
|
||||
merge-multiple: true
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- name: Install fixture dependencies
|
||||
working-directory: fixtures/flight
|
||||
run: |
|
||||
yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
|
||||
if [ $? -ne 0 ]; then
|
||||
yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
|
||||
fi
|
||||
- name: Playwright install deps
|
||||
working-directory: fixtures/flight
|
||||
run: |
|
||||
npx playwright install
|
||||
sudo npx playwright install-deps
|
||||
- name: Run tests
|
||||
working-directory: fixtures/flight
|
||||
run: yarn test
|
||||
@@ -491,17 +671,23 @@ jobs:
|
||||
with:
|
||||
name: flight-playwright-report
|
||||
path: fixtures/flight/playwright-report
|
||||
if-no-files-found: warn
|
||||
- name: Archive Flight fixture artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: flight-test-results
|
||||
path: fixtures/flight/test-results
|
||||
if-no-files-found: ignore
|
||||
|
||||
# ----- DEVTOOLS -----
|
||||
build_devtools_and_process_artifacts:
|
||||
name: Build DevTools and process artifacts
|
||||
needs: build_and_lint
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
browser: [chrome, firefox, edge]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -512,45 +698,52 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: _build_*
|
||||
path: build
|
||||
merge-multiple: true
|
||||
- run: ./scripts/ci/pack_and_store_devtools_artifacts.sh
|
||||
- run: ./scripts/ci/pack_and_store_devtools_artifacts.sh ${{ matrix.browser }}
|
||||
env:
|
||||
RELEASE_CHANNEL: experimental
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- name: Archive devtools build
|
||||
# Simplifies getting the extension for local testing
|
||||
- name: Archive ${{ matrix.browser }} extension
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: react-devtools-${{ matrix.browser }}-extension
|
||||
path: build/devtools/${{ matrix.browser }}-extension.zip
|
||||
if-no-files-found: error
|
||||
|
||||
merge_devtools_artifacts:
|
||||
name: Merge DevTools artifacts
|
||||
needs: build_devtools_and_process_artifacts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Merge artifacts
|
||||
uses: actions/upload-artifact/merge@v4
|
||||
with:
|
||||
name: react-devtools
|
||||
path: build/devtools.tgz
|
||||
# Simplifies getting the extension for local testing
|
||||
- name: Archive chrome extension
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: react-devtools-chrome-extension
|
||||
path: build/devtools/chrome-extension.zip
|
||||
- name: Archive firefox extension
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: react-devtools-firefox-extension
|
||||
path: build/devtools/firefox-extension.zip
|
||||
pattern: react-devtools-*-extension
|
||||
|
||||
run_devtools_e2e_tests:
|
||||
name: Run DevTools e2e tests
|
||||
needs: build_devtools_and_process_artifacts
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -562,14 +755,19 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache/restore@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-node_modules-v6-
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -584,52 +782,13 @@ jobs:
|
||||
RELEASE_CHANNEL: experimental
|
||||
|
||||
# ----- SIZEBOT -----
|
||||
download_base_build_for_sizebot:
|
||||
if: ${{ github.event_name == 'pull_request' && github.ref_name != 'main' }}
|
||||
name: Download base build for sizebot
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
- name: Download artifacts for base revision
|
||||
run: |
|
||||
git fetch origin main
|
||||
GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=$(git rev-parse origin/main)
|
||||
mv ./build ./base-build
|
||||
# TODO: The `download-experimental-build` script copies the npm
|
||||
# packages into the `node_modules` directory. This is a historical
|
||||
# quirk of how the release script works. Let's pretend they
|
||||
# don't exist.
|
||||
- name: Delete extraneous files
|
||||
run: rm -rf ./base-build/node_modules
|
||||
- name: Display structure of base-build
|
||||
run: ls -R base-build
|
||||
- name: Archive base-build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: base-build
|
||||
path: base-build
|
||||
|
||||
sizebot:
|
||||
if: ${{ github.event_name == 'pull_request' && github.ref_name != 'main' && github.event.pull_request.base.ref == 'main' }}
|
||||
name: Run sizebot
|
||||
needs: [build_and_lint, download_base_build_for_sizebot]
|
||||
needs: [build_and_lint]
|
||||
permissions:
|
||||
# We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
|
||||
actions: read
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -641,14 +800,36 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Download artifacts for base revision
|
||||
# The build could have been generated from a fork, so we must download the build without
|
||||
# any verification. This is safe since we only use this for sizebot calculation and the
|
||||
# unverified artifact is not used. Additionally this workflow runs in the pull_request
|
||||
# trigger so only restricted permissions are available.
|
||||
run: |
|
||||
GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=$(git rev-parse ${{ github.event.pull_request.base.sha }}) ${{ (github.event.pull_request.head.repo.full_name != github.repository && '--noVerify') || ''}}
|
||||
mv ./build ./base-build
|
||||
- name: Delete extraneous files
|
||||
# TODO: The `download-experimental-build` script copies the npm
|
||||
# packages into the `node_modules` directory. This is a historical
|
||||
# quirk of how the release script works. Let's pretend they
|
||||
# don't exist.
|
||||
run: rm -rf ./base-build/node_modules
|
||||
- name: Display structure of base-build from origin/main
|
||||
run: ls -R base-build
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- name: Restore archived build for PR
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -661,17 +842,11 @@ jobs:
|
||||
node ./scripts/print-warnings/print-warnings.js > build/__test_utils__/ReactAllWarnings.js
|
||||
- name: Display structure of build for PR
|
||||
run: ls -R build
|
||||
- name: Restore archived base-build from origin/main
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: base-build
|
||||
path: base-build
|
||||
- name: Display structure of base-build from origin/main
|
||||
run: ls -R base-build
|
||||
- run: echo ${{ github.sha }} >> build/COMMIT_SHA
|
||||
- run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA
|
||||
- run: node ./scripts/tasks/danger
|
||||
- name: Archive sizebot results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sizebot-message
|
||||
path: sizebot-message.md
|
||||
if-no-files-found: ignore
|
||||
|
||||
170
.github/workflows/runtime_commit_artifacts.yml
vendored
170
.github/workflows/runtime_commit_artifacts.yml
vendored
@@ -16,6 +16,13 @@ on:
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
dry_run:
|
||||
description: Perform a dry run (run everything except push)
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
@@ -25,6 +32,40 @@ env:
|
||||
jobs:
|
||||
download_artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
|
||||
actions: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Download artifacts for base revision
|
||||
run: |
|
||||
GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- name: Archive build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build
|
||||
path: build/
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
process_artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [download_artifacts]
|
||||
outputs:
|
||||
www_branch_count: ${{ steps.check_branches.outputs.www_branch_count }}
|
||||
fbsource_branch_count: ${{ steps.check_branches.outputs.fbsource_branch_count }}
|
||||
@@ -64,27 +105,11 @@ jobs:
|
||||
run: |
|
||||
echo "www_branch_count=$(git ls-remote --heads origin "refs/heads/meta-www" | wc -l)" >> "$GITHUB_OUTPUT"
|
||||
echo "fbsource_branch_count=$(git ls-remote --heads origin "refs/heads/meta-fbsource" | wc -l)" >> "$GITHUB_OUTPUT"
|
||||
- uses: actions/setup-node@v4
|
||||
- name: Restore downloaded build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
name: yarn install (react)
|
||||
- run: yarn install --frozen-lockfile
|
||||
name: yarn install (scripts/release)
|
||||
working-directory: scripts/release
|
||||
- name: Download artifacts for base revision
|
||||
run: |
|
||||
GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}
|
||||
name: build
|
||||
path: build
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- name: Strip @license from eslint plugin and react-refresh
|
||||
@@ -107,9 +132,10 @@ jobs:
|
||||
mkdir ./compiled/facebook-www/__test_utils__
|
||||
mv build/__test_utils__/ReactAllWarnings.js ./compiled/facebook-www/__test_utils__/ReactAllWarnings.js
|
||||
|
||||
# Move eslint-plugin-react-hooks into facebook-www
|
||||
# Move eslint-plugin-react-hooks into eslint-plugin-react-hooks
|
||||
mkdir ./compiled/eslint-plugin-react-hooks
|
||||
mv build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \
|
||||
./compiled/facebook-www/eslint-plugin-react-hooks.js
|
||||
./compiled/eslint-plugin-react-hooks/index.js
|
||||
|
||||
# Move unstable_server-external-runtime.js into facebook-www
|
||||
mv build/oss-experimental/react-dom/unstable_server-external-runtime.js \
|
||||
@@ -147,9 +173,9 @@ jobs:
|
||||
ls -R ./compiled-rn
|
||||
- name: Add REVISION files
|
||||
run: |
|
||||
echo ${{ github.sha }} >> ./compiled/facebook-www/REVISION
|
||||
echo ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} >> ./compiled/facebook-www/REVISION
|
||||
cp ./compiled/facebook-www/REVISION ./compiled/facebook-www/REVISION_TRANSFORMS
|
||||
echo ${{ github.sha}} >> ./compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION
|
||||
echo ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} >> ./compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION
|
||||
- name: "Get current version string"
|
||||
id: get_current_version
|
||||
run: |
|
||||
@@ -166,15 +192,20 @@ jobs:
|
||||
with:
|
||||
name: compiled
|
||||
path: compiled/
|
||||
if-no-files-found: error
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: compiled-rn
|
||||
path: compiled-rn/
|
||||
if-no-files-found: error
|
||||
|
||||
commit_www_artifacts:
|
||||
needs: download_artifacts
|
||||
if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.download_artifacts.outputs.www_branch_count == '0')
|
||||
needs: [download_artifacts, process_artifacts]
|
||||
if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.process_artifacts.outputs.www_branch_count == '0')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Used to push a commit to builds/facebook-www
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -186,12 +217,12 @@ jobs:
|
||||
name: compiled
|
||||
path: compiled/
|
||||
- name: Revert version changes
|
||||
if: needs.download_artifacts.outputs.last_version_classic != '' && needs.download_artifacts.outputs.last_version_modern != ''
|
||||
if: needs.process_artifacts.outputs.last_version_classic != '' && needs.process_artifacts.outputs.last_version_modern != ''
|
||||
env:
|
||||
CURRENT_VERSION_CLASSIC: ${{ needs.download_artifacts.outputs.current_version_classic }}
|
||||
CURRENT_VERSION_MODERN: ${{ needs.download_artifacts.outputs.current_version_modern }}
|
||||
LAST_VERSION_CLASSIC: ${{ needs.download_artifacts.outputs.last_version_classic }}
|
||||
LAST_VERSION_MODERN: ${{ needs.download_artifacts.outputs.last_version_modern }}
|
||||
CURRENT_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.current_version_classic }}
|
||||
CURRENT_VERSION_MODERN: ${{ needs.process_artifacts.outputs.current_version_modern }}
|
||||
LAST_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.last_version_classic }}
|
||||
LAST_VERSION_MODERN: ${{ needs.process_artifacts.outputs.last_version_modern }}
|
||||
run: |
|
||||
echo "Reverting $CURRENT_VERSION_CLASSIC to $LAST_VERSION_CLASSIC"
|
||||
grep -rl "$CURRENT_VERSION_CLASSIC" ./compiled || echo "No files found with $CURRENT_VERSION_CLASSIC"
|
||||
@@ -221,12 +252,12 @@ jobs:
|
||||
echo "should_commit=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Re-apply version changes
|
||||
if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_classic != '' && needs.download_artifacts.outputs.last_version_modern != '')
|
||||
if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.process_artifacts.outputs.last_version_classic != '' && needs.process_artifacts.outputs.last_version_modern != '')
|
||||
env:
|
||||
CURRENT_VERSION_CLASSIC: ${{ needs.download_artifacts.outputs.current_version_classic }}
|
||||
CURRENT_VERSION_MODERN: ${{ needs.download_artifacts.outputs.current_version_modern }}
|
||||
LAST_VERSION_CLASSIC: ${{ needs.download_artifacts.outputs.last_version_classic }}
|
||||
LAST_VERSION_MODERN: ${{ needs.download_artifacts.outputs.last_version_modern }}
|
||||
CURRENT_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.current_version_classic }}
|
||||
CURRENT_VERSION_MODERN: ${{ needs.process_artifacts.outputs.current_version_modern }}
|
||||
LAST_VERSION_CLASSIC: ${{ needs.process_artifacts.outputs.last_version_classic }}
|
||||
LAST_VERSION_MODERN: ${{ needs.process_artifacts.outputs.last_version_modern }}
|
||||
run: |
|
||||
echo "Re-applying $LAST_VERSION_CLASSIC to $CURRENT_VERSION_CLASSIC"
|
||||
grep -rl "$LAST_VERSION_CLASSIC" ./compiled || echo "No files found with $LAST_VERSION_CLASSIC"
|
||||
@@ -240,24 +271,31 @@ jobs:
|
||||
- name: Will commit these changes
|
||||
if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
|
||||
run: |
|
||||
echo ":"
|
||||
git status -u
|
||||
git add .
|
||||
git status
|
||||
- name: Check commit message
|
||||
if: inputs.dry_run
|
||||
run: |
|
||||
git fetch origin --quiet
|
||||
git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:"%B"
|
||||
- name: Commit changes to branch
|
||||
if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: |
|
||||
${{ github.event.workflow_run.head_commit.message || format('Manual build of {0}', github.event.workflow_run.head_sha || github.sha) }}
|
||||
run: |
|
||||
git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}"
|
||||
git config --global user.name "${{ github.triggering_actor }}"
|
||||
|
||||
DiffTrain build for [${{ github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha || github.sha }})
|
||||
branch: builds/facebook-www
|
||||
commit_user_name: ${{ github.triggering_actor }}
|
||||
commit_user_email: ${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}
|
||||
create_branch: true
|
||||
git fetch origin --quiet
|
||||
git commit -m "$(git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:'%B%n%nDiffTrain build for [${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha}})')" || echo "No changes to commit"
|
||||
- name: Push changes to branch
|
||||
if: inputs.dry_run == false && (inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true')
|
||||
run: git push
|
||||
|
||||
commit_fbsource_artifacts:
|
||||
needs: download_artifacts
|
||||
if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.download_artifacts.outputs.fbsource_branch_count == '0')
|
||||
needs: [download_artifacts, process_artifacts]
|
||||
permissions:
|
||||
# Used to push a commit to builds/facebook-fbsource
|
||||
contents: write
|
||||
if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.process_artifacts.outputs.fbsource_branch_count == '0')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -270,10 +308,10 @@ jobs:
|
||||
name: compiled-rn
|
||||
path: compiled-rn/
|
||||
- name: Revert version changes
|
||||
if: needs.download_artifacts.outputs.last_version_rn != ''
|
||||
if: needs.process_artifacts.outputs.last_version_rn != ''
|
||||
env:
|
||||
CURRENT_VERSION: ${{ needs.download_artifacts.outputs.current_version_rn }}
|
||||
LAST_VERSION: ${{ needs.download_artifacts.outputs.last_version_rn }}
|
||||
CURRENT_VERSION: ${{ needs.process_artifacts.outputs.current_version_rn }}
|
||||
LAST_VERSION: ${{ needs.process_artifacts.outputs.last_version_rn }}
|
||||
run: |
|
||||
echo "Reverting $CURRENT_VERSION to $LAST_VERSION"
|
||||
grep -rl "$CURRENT_VERSION" ./compiled-rn || echo "No files found with $CURRENT_VERSION"
|
||||
@@ -299,10 +337,10 @@ jobs:
|
||||
echo "should_commit=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Re-apply version changes
|
||||
if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_rn != '')
|
||||
if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.process_artifacts.outputs.last_version_rn != '')
|
||||
env:
|
||||
CURRENT_VERSION: ${{ needs.download_artifacts.outputs.current_version_rn }}
|
||||
LAST_VERSION: ${{ needs.download_artifacts.outputs.last_version_rn }}
|
||||
CURRENT_VERSION: ${{ needs.process_artifacts.outputs.current_version_rn }}
|
||||
LAST_VERSION: ${{ needs.process_artifacts.outputs.last_version_rn }}
|
||||
run: |
|
||||
echo "Re-applying $LAST_VERSION to $CURRENT_VERSION"
|
||||
grep -rl "$LAST_VERSION" ./compiled-rn || echo "No files found with $LAST_VERSION"
|
||||
@@ -409,15 +447,19 @@ jobs:
|
||||
run: |
|
||||
git add .
|
||||
git status
|
||||
- name: Check commit message
|
||||
if: inputs.dry_run
|
||||
run: |
|
||||
git fetch origin --quiet
|
||||
git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:"%B"
|
||||
- name: Commit changes to branch
|
||||
if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: |
|
||||
${{ github.event.workflow_run.head_commit.message || format('Manual build of {0}', github.event.workflow_run.head_sha || github.sha) }}
|
||||
run: |
|
||||
git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}"
|
||||
git config --global user.name "${{ github.triggering_actor }}"
|
||||
|
||||
DiffTrain build for [${{ github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha || github.sha }})
|
||||
branch: builds/facebook-fbsource
|
||||
commit_user_name: ${{ github.triggering_actor }}
|
||||
commit_user_email: ${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}
|
||||
create_branch: true
|
||||
git fetch origin --quiet
|
||||
git commit -m "$(git show ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} --no-patch --pretty=format:'%B%n%nDiffTrain build for [${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha}})')" || echo "No changes to commit"
|
||||
- name: Push changes to branch
|
||||
if: inputs.dry_run == false && (inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true')
|
||||
run: git push
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
name: (Shared) Discord Notify
|
||||
name: (Runtime) Discord Notify
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
types: [opened, ready_for_review]
|
||||
paths-ignore:
|
||||
- compiler/**
|
||||
- .github/workflows/compiler_**.yml
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
check_maintainer:
|
||||
uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
|
||||
permissions:
|
||||
# Used by check_maintainer
|
||||
contents: read
|
||||
with:
|
||||
actor: ${{ github.event.pull_request.user.login }}
|
||||
|
||||
notify:
|
||||
if: ${{ github.event.label.name == 'React Core Team' }}
|
||||
if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }}
|
||||
needs: check_maintainer
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Discord Webhook Action
|
||||
uses: tsickert/discord-webhook@v6.0.0
|
||||
uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
|
||||
with:
|
||||
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
embed-author-name: ${{ github.event.pull_request.user.login }}
|
||||
65
.github/workflows/runtime_eslint_plugin_e2e.yml
vendored
Normal file
65
.github/workflows/runtime_eslint_plugin_e2e.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
name: (Runtime) ESLint Plugin E2E
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- compiler/**
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
jobs:
|
||||
# ----- TESTS -----
|
||||
test:
|
||||
name: ESLint v${{ matrix.eslint_major }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
eslint_major:
|
||||
- "6"
|
||||
- "7"
|
||||
- "8"
|
||||
- "9"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-eslint_e2e-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock', 'fixtures/eslint-v*/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Install fixture dependencies
|
||||
working-directory: ./fixtures/eslint-v${{ matrix.eslint_major }}
|
||||
run: yarn --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Build plugin
|
||||
working-directory: fixtures/eslint-v${{ matrix.eslint_major }}
|
||||
run: node build.mjs
|
||||
- name: Run lint test
|
||||
working-directory: ./fixtures/eslint-v${{ matrix.eslint_major }}
|
||||
run: yarn lint
|
||||
2
.github/workflows/runtime_fuzz_tests.yml
vendored
2
.github/workflows/runtime_fuzz_tests.yml
vendored
@@ -8,6 +8,8 @@ on:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
|
||||
20
.github/workflows/runtime_prereleases.yml
vendored
20
.github/workflows/runtime_prereleases.yml
vendored
@@ -14,20 +14,26 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
GH_TOKEN:
|
||||
required: true
|
||||
NPM_TOKEN:
|
||||
required: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
jobs:
|
||||
publish_prerelease:
|
||||
name: Publish prelease (${{ inputs.release_channel }}) ${{ inputs.commit_sha }} @${{ inputs.dist_tag }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
|
||||
actions: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@@ -39,14 +45,16 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: |
|
||||
scripts/release/prepare-release-from-ci.js --skipTests -r ${{ inputs.release_channel }} --commit=${{ inputs.commit_sha }}
|
||||
GH_TOKEN=${{ secrets.GH_TOKEN }} scripts/release/prepare-release-from-ci.js --skipTests -r ${{ inputs.release_channel }} --commit=${{ inputs.commit_sha }}
|
||||
cp ./scripts/release/ci-npmrc ~/.npmrc
|
||||
scripts/release/publish.js --ci --tags ${{ inputs.dist_tag }}
|
||||
|
||||
10
.github/workflows/runtime_prereleases_manual.yml
vendored
10
.github/workflows/runtime_prereleases_manual.yml
vendored
@@ -6,6 +6,8 @@ on:
|
||||
prerelease_commit_sha:
|
||||
required: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
@@ -14,6 +16,9 @@ jobs:
|
||||
publish_prerelease_canary:
|
||||
name: Publish to Canary channel
|
||||
uses: facebook/react/.github/workflows/runtime_prereleases.yml@main
|
||||
permissions:
|
||||
# We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
|
||||
actions: read
|
||||
with:
|
||||
commit_sha: ${{ inputs.prerelease_commit_sha }}
|
||||
release_channel: stable
|
||||
@@ -30,10 +35,14 @@ jobs:
|
||||
dist_tag: canary,next
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
publish_prerelease_experimental:
|
||||
name: Publish to Experimental channel
|
||||
uses: facebook/react/.github/workflows/runtime_prereleases.yml@main
|
||||
permissions:
|
||||
# We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
|
||||
actions: read
|
||||
# NOTE: Intentionally running these jobs sequentially because npm
|
||||
# will sometimes fail if you try to concurrently publish two
|
||||
# different versions of the same package, even if they use different
|
||||
@@ -45,3 +54,4 @@ jobs:
|
||||
dist_tag: experimental
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -5,6 +5,8 @@ on:
|
||||
# At 10 minutes past 16:00 on Mon, Tue, Wed, Thu, and Fri
|
||||
- cron: 10 16 * * 1,2,3,4,5
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
@@ -12,16 +14,23 @@ jobs:
|
||||
publish_prerelease_canary:
|
||||
name: Publish to Canary channel
|
||||
uses: facebook/react/.github/workflows/runtime_prereleases.yml@main
|
||||
permissions:
|
||||
# We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
|
||||
actions: read
|
||||
with:
|
||||
commit_sha: ${{ github.sha }}
|
||||
release_channel: stable
|
||||
dist_tag: canary,next
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
publish_prerelease_experimental:
|
||||
name: Publish to Experimental channel
|
||||
uses: facebook/react/.github/workflows/runtime_prereleases.yml@main
|
||||
permissions:
|
||||
# We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
|
||||
actions: read
|
||||
# NOTE: Intentionally running these jobs sequentially because npm
|
||||
# will sometimes fail if you try to concurrently publish two
|
||||
# different versions of the same package, even if they use different
|
||||
@@ -33,3 +42,4 @@ jobs:
|
||||
dist_tag: experimental
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
128
.github/workflows/runtime_releases_from_npm_manual.yml
vendored
Normal file
128
.github/workflows/runtime_releases_from_npm_manual.yml
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
name: (Runtime) Publish Releases from NPM Manual
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version_to_promote:
|
||||
required: true
|
||||
description: Current npm version (non-experimental) to promote
|
||||
type: string
|
||||
version_to_publish:
|
||||
required: true
|
||||
description: Version to publish for the specified packages
|
||||
type: string
|
||||
only_packages:
|
||||
description: Packages to publish (space separated)
|
||||
type: string
|
||||
skip_packages:
|
||||
description: Packages to NOT publish (space separated)
|
||||
type: string
|
||||
tags:
|
||||
description: NPM tags (space separated)
|
||||
type: string
|
||||
default: untagged
|
||||
dry:
|
||||
required: true
|
||||
description: Dry run instead of publish?
|
||||
type: boolean
|
||||
default: true
|
||||
force_notify:
|
||||
description: Force a Discord notification?
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
jobs:
|
||||
notify:
|
||||
if: ${{ inputs.force_notify || inputs.dry == false || inputs.dry == 'false' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Discord Webhook Action
|
||||
uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
|
||||
with:
|
||||
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
embed-author-name: ${{ github.event.sender.login }}
|
||||
embed-author-url: ${{ github.event.sender.html_url }}
|
||||
embed-author-icon-url: ${{ github.event.sender.avatar_url }}
|
||||
embed-title: "⚠️ Publishing release from NPM${{ (inputs.dry && ' (dry run)') || '' }}"
|
||||
embed-description: |
|
||||
```json
|
||||
${{ toJson(inputs) }}
|
||||
```
|
||||
embed-url: https://github.com/facebook/react/actions/runs/${{ github.run_id }}
|
||||
|
||||
publish:
|
||||
name: Publish releases
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-release-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: cp ./scripts/release/ci-npmrc ~/.npmrc
|
||||
- if: '${{ inputs.only_packages }}'
|
||||
name: 'Prepare ${{ inputs.only_packages }} from NPM'
|
||||
run: |
|
||||
scripts/release/prepare-release-from-npm.js \
|
||||
--ci \
|
||||
--skipTests \
|
||||
--version=${{ inputs.version_to_promote }} \
|
||||
--publishVersion=${{ inputs.version_to_publish }} \
|
||||
--onlyPackages=${{ inputs.only_packages }}
|
||||
- if: '${{ inputs.skip_packages }}'
|
||||
name: 'Prepare all packages EXCEPT ${{ inputs.skip_packages }} from NPM'
|
||||
run: |
|
||||
scripts/release/prepare-release-from-npm.js \
|
||||
--ci \
|
||||
--skipTests \
|
||||
--version=${{ inputs.version_to_promote }} \
|
||||
--publishVersion=${{ inputs.version_to_publish }} \
|
||||
--skipPackages=${{ inputs.skip_packages }}
|
||||
- name: Check prepared files
|
||||
run: ls -R build/node_modules
|
||||
- if: '${{ inputs.only_packages }}'
|
||||
name: 'Publish ${{ inputs.only_packages }}'
|
||||
run: |
|
||||
scripts/release/publish.js \
|
||||
--ci \
|
||||
--tags=${{ inputs.tags }} \
|
||||
--publishVersion=${{ inputs.version_to_publish }} \
|
||||
--onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}}
|
||||
${{ inputs.dry && '--dry'}}
|
||||
- if: '${{ inputs.skip_packages }}'
|
||||
name: 'Publish all packages EXCEPT ${{ inputs.skip_packages }}'
|
||||
run: |
|
||||
scripts/release/publish.js \
|
||||
--ci \
|
||||
--tags=${{ inputs.tags }} \
|
||||
--publishVersion=${{ inputs.version_to_publish }} \
|
||||
--skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}}
|
||||
${{ inputs.dry && '--dry'}}
|
||||
- name: Archive released package for debugging
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build
|
||||
path: |
|
||||
./build/node_modules
|
||||
58
.github/workflows/shared_check_maintainer.yml
vendored
Normal file
58
.github/workflows/shared_check_maintainer.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: (Shared) Check maintainer
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
actor:
|
||||
required: true
|
||||
type: string
|
||||
outputs:
|
||||
is_core_team:
|
||||
value: ${{ jobs.check_maintainer.outputs.is_core_team }}
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
|
||||
|
||||
jobs:
|
||||
check_maintainer:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# We fetch the contents of the MAINTAINERS file
|
||||
contents: read
|
||||
outputs:
|
||||
is_core_team: ${{ steps.check_if_actor_is_maintainer.outputs.result }}
|
||||
steps:
|
||||
- name: Check if actor is maintainer
|
||||
id: check_if_actor_is_maintainer
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const actor = '${{ inputs.actor }}';
|
||||
const res = await github.rest.repos.getContent({
|
||||
owner: 'facebook',
|
||||
repo: 'react',
|
||||
path: 'MAINTAINERS',
|
||||
ref: 'main',
|
||||
headers: { Accept: 'application/vnd.github+json' }
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
console.error(res);
|
||||
throw new Error('Unable to fetch MAINTAINERS file');
|
||||
}
|
||||
content = Buffer.from(res.data.content, 'base64').toString();
|
||||
if (content == null || typeof content !== 'string') {
|
||||
throw new Error('Unable to retrieve MAINTAINERS file');
|
||||
}
|
||||
|
||||
const maintainers = new Set(content.split('\n'));
|
||||
if (maintainers.has(actor)) {
|
||||
console.log(`🟢 ${actor} is a maintainer`);
|
||||
return true;
|
||||
}
|
||||
console.log(`🔴 ${actor} is NOT a maintainer`);
|
||||
return null;
|
||||
41
.github/workflows/shared_cleanup_merged_branch_caches.yml
vendored
Normal file
41
.github/workflows/shared_cleanup_merged_branch_caches.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy
|
||||
|
||||
name: (Shared) Cleanup Merged Branch Caches
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
cleanup:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# `actions:write` permission is required to delete caches
|
||||
# See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id
|
||||
actions: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
echo "Fetching list of cache key"
|
||||
cacheKeysForPR=$(gh cache list --ref $BRANCH --limit 100 --json id --jq '.[].id')
|
||||
|
||||
## Setting this to not fail the workflow while deleting cache keys.
|
||||
set +e
|
||||
for cacheKey in $cacheKeysForPR
|
||||
do
|
||||
gh cache delete $cacheKey
|
||||
echo "Deleting $cacheKey"
|
||||
done
|
||||
echo "Done"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
BRANCH: refs/pull/${{ inputs.pr_number || github.event.pull_request.number }}/merge
|
||||
36
.github/workflows/shared_cleanup_stale_branch_caches.yml
vendored
Normal file
36
.github/workflows/shared_cleanup_stale_branch_caches.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy
|
||||
|
||||
name: (Shared) Cleanup Stale Branch Caches
|
||||
on:
|
||||
schedule:
|
||||
# Every 6 hours
|
||||
- cron: 0 */6 * * *
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
cleanup:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# `actions:write` permission is required to delete caches
|
||||
# See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id
|
||||
actions: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Cleanup
|
||||
run: |
|
||||
echo "Fetching list of cache keys"
|
||||
cacheKeysForPR=$(gh cache list --limit 100 --json id,ref --jq '.[] | select(.ref != "refs/heads/main") | .id')
|
||||
|
||||
## Setting this to not fail the workflow while deleting cache keys.
|
||||
set +e
|
||||
for cacheKey in $cacheKeysForPR
|
||||
do
|
||||
gh cache delete $cacheKey
|
||||
echo "Deleting $cacheKey"
|
||||
done
|
||||
echo "Done"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
42
.github/workflows/shared_close_direct_sync_branch_prs.yml
vendored
Normal file
42
.github/workflows/shared_close_direct_sync_branch_prs.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: (Shared) Close Direct Sync Branch PRs
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- 'builds/facebook-**'
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
|
||||
|
||||
jobs:
|
||||
close_pr:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Used to create a review and close PRs
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Close PR
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const pullNumber = ${{ github.event.number }};
|
||||
|
||||
await github.rest.pulls.createReview({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pullNumber,
|
||||
body: 'Do not land changes to `${{ github.event.pull_request.base.ref }}`. Please re-open your PR targeting `main` instead.',
|
||||
event: 'REQUEST_CHANGES'
|
||||
});
|
||||
await github.rest.pulls.update({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pullNumber,
|
||||
state: 'closed'
|
||||
});
|
||||
41
.github/workflows/shared_label_core_team_prs.yml
vendored
Normal file
41
.github/workflows/shared_label_core_team_prs.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: (Shared) Label Core Team PRs
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
|
||||
|
||||
jobs:
|
||||
check_maintainer:
|
||||
uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main
|
||||
permissions:
|
||||
# Used by check_maintainer
|
||||
contents: read
|
||||
with:
|
||||
actor: ${{ github.event.pull_request.user.login }}
|
||||
|
||||
label:
|
||||
if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: check_maintainer
|
||||
permissions:
|
||||
# Used to add labels on issues
|
||||
issues: write
|
||||
# Used to add labels on PRs
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Label PR as React Core Team
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: ${{ github.event.number }},
|
||||
labels: ['React Core Team']
|
||||
});
|
||||
30
.github/workflows/shared_lint.yml
vendored
30
.github/workflows/shared_lint.yml
vendored
@@ -5,6 +5,8 @@ on:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
@@ -27,12 +29,15 @@ jobs:
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn prettier-check
|
||||
|
||||
eslint:
|
||||
@@ -47,12 +52,15 @@ jobs:
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: node ./scripts/tasks/eslint
|
||||
|
||||
check_license:
|
||||
@@ -67,12 +75,15 @@ jobs:
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: ./scripts/ci/check_license.sh
|
||||
|
||||
test_print_warnings:
|
||||
@@ -87,10 +98,13 @@ jobs:
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: ./scripts/ci/test_print_warnings.sh
|
||||
|
||||
2
.github/workflows/shared_stale.yml
vendored
2
.github/workflows/shared_stale.yml
vendored
@@ -6,6 +6,8 @@ on:
|
||||
- cron: '0 * * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -37,3 +37,4 @@ packages/react-devtools-fusebox/dist
|
||||
packages/react-devtools-inline/dist
|
||||
packages/react-devtools-shell/dist
|
||||
packages/react-devtools-timeline/dist
|
||||
|
||||
|
||||
22
MAINTAINERS
Normal file
22
MAINTAINERS
Normal file
@@ -0,0 +1,22 @@
|
||||
acdlite
|
||||
eps1lon
|
||||
gaearon
|
||||
gnoff
|
||||
unstubbable
|
||||
hoxyq
|
||||
jackpope
|
||||
jbonta
|
||||
jbrown215
|
||||
josephsavona
|
||||
kassens
|
||||
mattcarrollcode
|
||||
mofeiZ
|
||||
mvitousek
|
||||
pieterv
|
||||
poteto
|
||||
rickhanlonii
|
||||
sebmarkbage
|
||||
sethwebster
|
||||
sophiebits
|
||||
elicwhite
|
||||
yuzhi
|
||||
19
babel.config-react-compiler.js
Normal file
19
babel.config-react-compiler.js
Normal file
@@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* HACK: @poteto React Compiler inlines Zod in its build artifact. Zod spreads values passed to .map
|
||||
* which causes issues in @babel/plugin-transform-spread in loose mode, as it will result in
|
||||
* {undefined: undefined} which fails to parse.
|
||||
*
|
||||
* [@babel/plugin-transform-block-scoping', {throwIfClosureRequired: true}] also causes issues with
|
||||
* the built version of the compiler. The minimal set of plugins needed for this file is reexported
|
||||
* from babel.config-ts.
|
||||
*
|
||||
* I will remove this hack later when we move eslint-plugin-react-hooks into the compiler directory.
|
||||
**/
|
||||
|
||||
const baseConfig = require('./babel.config-ts');
|
||||
|
||||
module.exports = {
|
||||
plugins: baseConfig.plugins,
|
||||
};
|
||||
17
babel.config-ts.js
Normal file
17
babel.config-ts.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* This file is purely being used for local jest runs, and doesn't participate in the build process.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
'@babel/plugin-syntax-jsx',
|
||||
'@babel/plugin-transform-flow-strip-types',
|
||||
['@babel/plugin-transform-class-properties', {loose: true}],
|
||||
'@babel/plugin-transform-classes',
|
||||
],
|
||||
presets: [
|
||||
['@babel/preset-env', {targets: {node: 'current'}}],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
};
|
||||
6
compiler/.gitignore
vendored
6
compiler/.gitignore
vendored
@@ -21,4 +21,8 @@ dist
|
||||
.spr.yml
|
||||
testfilter.txt
|
||||
|
||||
bundle-oss.sh
|
||||
bundle-oss.sh
|
||||
|
||||
# forgive
|
||||
*.vsix
|
||||
.vscode-test
|
||||
|
||||
1217
compiler/Cargo.lock
generated
1217
compiler/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,61 +0,0 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["crates/*"]
|
||||
|
||||
[workspace.package]
|
||||
authors = ["The React Team https://react.dev/community/team"]
|
||||
description = "React Compiler"
|
||||
edition = "2021"
|
||||
homepage = "https://github.com/facebook/react"
|
||||
keywords = ["JavaScript", "TypeScript", "React", "React Compiler", "Compiler"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/facebook/react"
|
||||
|
||||
[workspace.dependencies]
|
||||
# workspace crates
|
||||
react_build_hir = { path = "crates/react_build_hir" }
|
||||
react_diagnostics = { path = "crates/react_diagnostics" }
|
||||
react_estree = { path = "crates/react_estree" }
|
||||
react_estree_codegen = { path = "crates/react_estree_codegen" }
|
||||
react_fixtures = { path = "crates/react_fixtures" }
|
||||
react_hermes_parser = { path = "crates/react_hermes_parser" }
|
||||
react_hir = { path = "crates/react_hir" }
|
||||
react_optimization = { path = "crates/react_optimization" }
|
||||
react_semantic_analysis = { path = "crates/react_semantic_analysis" }
|
||||
react_ssa = { path = "crates/react_ssa" }
|
||||
react_utils = { path = "crates/react_utils" }
|
||||
|
||||
# dependencies
|
||||
indexmap = { version = "2.0.0", features = ["serde"] }
|
||||
insta = { version = "1.30.0", features = ["glob"] }
|
||||
miette = { version = "5.9.0" }
|
||||
prettyplease = "0.2.10"
|
||||
quote = "1.0.29"
|
||||
serde = { version = "1.0.167", features = ["serde_derive"] }
|
||||
serde_json = "1.0.100"
|
||||
stacker = "0.1.15"
|
||||
static_assertions = "1.1.0"
|
||||
syn = "2.0.23"
|
||||
thiserror = "1.0.41"
|
||||
hermes = { git = "https://github.com/facebook/hermes.git" }
|
||||
juno_support = { git = "https://github.com/facebook/hermes.git" }
|
||||
|
||||
[profile.release]
|
||||
# configuration adapted from oxc
|
||||
# https://github.com/Boshen/oxc/blob/ea85ee9f2d64dd284c5b7410f491d81fb879abae/Cargo.toml#L89-L97
|
||||
opt-level = 3
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
strip = "symbols"
|
||||
debug = false
|
||||
panic = "abort" # Let it crash and force ourselves to write safe Rust.
|
||||
|
||||
# Make insta run faster by compiling with release mode optimizations
|
||||
# https://docs.rs/insta/latest/insta/#optional-faster-runs
|
||||
[profile.dev.package.insta]
|
||||
opt-level = 3
|
||||
|
||||
# Make insta diffing libary faster by compiling with release mode optimizations
|
||||
# https://docs.rs/insta/latest/insta/#optional-faster-runs
|
||||
[profile.dev.package.similar]
|
||||
opt-level = 3
|
||||
@@ -9,6 +9,13 @@ import {expect, test} from '@playwright/test';
|
||||
import {encodeStore, type Store} from '../../lib/stores';
|
||||
import {format} from 'prettier';
|
||||
|
||||
function isMonacoLoaded(): boolean {
|
||||
return (
|
||||
typeof window['MonacoEnvironment'] !== 'undefined' &&
|
||||
window['__MONACO_LOADED__'] === true
|
||||
);
|
||||
}
|
||||
|
||||
function formatPrint(data: Array<string>): Promise<string> {
|
||||
return format(data.join(''), {parser: 'babel'});
|
||||
}
|
||||
@@ -105,6 +112,7 @@ function nonReactFn() {
|
||||
|
||||
test('editor should open successfully', async ({page}) => {
|
||||
await page.goto(`/`, {waitUntil: 'networkidle'});
|
||||
await page.waitForFunction(isMonacoLoaded);
|
||||
await page.screenshot({
|
||||
fullPage: true,
|
||||
path: 'test-results/00-fresh-page.png',
|
||||
@@ -120,6 +128,7 @@ test('editor should compile from hash successfully', async ({page}) => {
|
||||
};
|
||||
const hash = encodeStore(store);
|
||||
await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
|
||||
await page.waitForFunction(isMonacoLoaded);
|
||||
|
||||
// User input from hash compiles
|
||||
await page.screenshot({
|
||||
@@ -143,6 +152,7 @@ test('reset button works', async ({page}) => {
|
||||
};
|
||||
const hash = encodeStore(store);
|
||||
await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
|
||||
await page.waitForFunction(isMonacoLoaded);
|
||||
|
||||
// Reset button works
|
||||
page.on('dialog', dialog => dialog.accept());
|
||||
@@ -166,6 +176,7 @@ TEST_CASE_INPUTS.forEach((t, idx) =>
|
||||
};
|
||||
const hash = encodeStore(store);
|
||||
await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
|
||||
await page.waitForFunction(isMonacoLoaded);
|
||||
await page.screenshot({
|
||||
fullPage: true,
|
||||
path: `test-results/03-0${idx}-${t.name}.png`,
|
||||
|
||||
@@ -19,7 +19,9 @@ import BabelPluginReactCompiler, {
|
||||
PluginOptions,
|
||||
CompilerPipelineValue,
|
||||
parsePluginOptions,
|
||||
} from 'babel-plugin-react-compiler/src';
|
||||
printReactiveFunctionWithOutlined,
|
||||
printFunctionWithOutlined,
|
||||
} from 'babel-plugin-react-compiler';
|
||||
import clsx from 'clsx';
|
||||
import invariant from 'invariant';
|
||||
import {useSnackbar} from 'notistack';
|
||||
@@ -41,8 +43,6 @@ import {
|
||||
default as Output,
|
||||
PrintedCompilerPipelineValue,
|
||||
} from './Output';
|
||||
import {printFunctionWithOutlined} from 'babel-plugin-react-compiler/src/HIR/PrintHIR';
|
||||
import {printReactiveFunctionWithOutlined} from 'babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction';
|
||||
import {transformFromAstSync} from '@babel/core';
|
||||
|
||||
function parseInput(
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react';
|
||||
import {CompilerErrorDetail} from 'babel-plugin-react-compiler/src';
|
||||
import {CompilerErrorDetail} from 'babel-plugin-react-compiler';
|
||||
import invariant from 'invariant';
|
||||
import type {editor} from 'monaco-editor';
|
||||
import * as monaco from 'monaco-editor';
|
||||
@@ -89,6 +89,9 @@ export default function Input({errors, language}: Props): JSX.Element {
|
||||
_: editor.IStandaloneCodeEditor,
|
||||
monaco: Monaco,
|
||||
) => void = (_, monaco) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
window['__MONACO_LOADED__'] = true;
|
||||
}
|
||||
setMonaco(monaco);
|
||||
|
||||
const tscOptions = {
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
InformationCircleIcon,
|
||||
} from '@heroicons/react/outline';
|
||||
import MonacoEditor, {DiffEditor} from '@monaco-editor/react';
|
||||
import {type CompilerError} from 'babel-plugin-react-compiler/src';
|
||||
import {type CompilerError} from 'babel-plugin-react-compiler';
|
||||
import parserBabel from 'prettier/plugins/babel';
|
||||
import * as prettierPluginEstree from 'prettier/plugins/estree';
|
||||
import * as prettier from 'prettier/standalone';
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
*/
|
||||
|
||||
import type {Dispatch, ReactNode} from 'react';
|
||||
import {useReducer} from 'react';
|
||||
import {useEffect, useReducer} from 'react';
|
||||
import createContext from '../lib/createContext';
|
||||
import {emptyStore} from '../lib/defaultStore';
|
||||
import type {Store} from '../lib/stores';
|
||||
import {saveStore} from '../lib/stores';
|
||||
import {saveStore, type Store} from '../lib/stores';
|
||||
|
||||
const StoreContext = createContext<Store>();
|
||||
|
||||
@@ -31,6 +30,11 @@ export const useStoreDispatch = StoreDispatchContext.useContext;
|
||||
*/
|
||||
export function StoreProvider({children}: {children: ReactNode}): JSX.Element {
|
||||
const [store, dispatch] = useReducer(storeReducer, emptyStore);
|
||||
useEffect(() => {
|
||||
if (store !== emptyStore) {
|
||||
saveStore(store);
|
||||
}
|
||||
}, [store]);
|
||||
|
||||
return (
|
||||
<StoreContext.Provider value={store}>
|
||||
@@ -59,19 +63,14 @@ function storeReducer(store: Store, action: ReducerAction): Store {
|
||||
switch (action.type) {
|
||||
case 'setStore': {
|
||||
const newStore = action.payload.store;
|
||||
|
||||
saveStore(newStore);
|
||||
return newStore;
|
||||
}
|
||||
case 'updateFile': {
|
||||
const {source} = action.payload;
|
||||
|
||||
const newStore = {
|
||||
...store,
|
||||
source,
|
||||
};
|
||||
|
||||
saveStore(newStore);
|
||||
return newStore;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
import {Monaco} from '@monaco-editor/react';
|
||||
import {
|
||||
CompilerErrorDetail,
|
||||
ErrorSeverity,
|
||||
} from 'babel-plugin-react-compiler/src';
|
||||
import {CompilerErrorDetail, ErrorSeverity} from 'babel-plugin-react-compiler';
|
||||
import {MarkerSeverity, type editor} from 'monaco-editor';
|
||||
|
||||
function mapReactCompilerSeverityToMonaco(
|
||||
@@ -54,7 +51,7 @@ export function renderReactCompilerMarkers({
|
||||
model,
|
||||
details,
|
||||
}: ReactCompilerMarkerConfig): void {
|
||||
let markers = [];
|
||||
const markers: Array<editor.IMarkerData> = [];
|
||||
for (const detail of details) {
|
||||
const marker = mapReactCompilerDiagnosticToMonacoMarker(detail, monaco);
|
||||
if (marker == null) {
|
||||
|
||||
2
compiler/apps/playground/next-env.d.ts
vendored
2
compiler/apps/playground/next-env.d.ts
vendored
@@ -2,4 +2,4 @@
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "cd ../.. && concurrently --kill-others -n compiler,runtime,playground \"yarn workspace babel-plugin-react-compiler run watch\" \"yarn workspace react-compiler-runtime run watch\" \"wait-on packages/babel-plugin-react-compiler/dist/index.js && cd apps/playground && NODE_ENV=development next dev\"",
|
||||
"build:compiler": "cd ../.. && concurrently -n compiler,runtime \"yarn workspace babel-plugin-react-compiler run build\" \"yarn workspace react-compiler-runtime run build\"",
|
||||
"build:compiler": "cd ../.. && concurrently -n compiler,runtime \"yarn workspace babel-plugin-react-compiler run build --dts\" \"yarn workspace react-compiler-runtime run build\"",
|
||||
"build": "yarn build:compiler && next build",
|
||||
"postbuild": "node ./scripts/downloadFonts.js",
|
||||
"preinstall": "cd ../.. && yarn install --frozen-lockfile",
|
||||
@@ -12,7 +12,7 @@
|
||||
"vercel-build": "yarn build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"test": "playwright test"
|
||||
"test": "playwright test --workers=4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.18.9",
|
||||
@@ -22,9 +22,9 @@
|
||||
"@babel/plugin-transform-block-scoping": "^7.18.9",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.18.9",
|
||||
"@babel/preset-react": "^7.18.9",
|
||||
"@babel/preset-typescript": "^7.18.9",
|
||||
"@babel/preset-typescript": "^7.26.0",
|
||||
"@babel/traverse": "^7.18.9",
|
||||
"@babel/types": "7.18.9",
|
||||
"@babel/types": "7.26.3",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@monaco-editor/react": "^4.4.6",
|
||||
"@playwright/test": "^1.42.1",
|
||||
@@ -34,18 +34,18 @@
|
||||
"invariant": "^2.2.4",
|
||||
"lz-string": "^1.5.0",
|
||||
"monaco-editor": "^0.52.0",
|
||||
"next": "^15.0.1",
|
||||
"next": "^15.2.0-canary.64",
|
||||
"notistack": "^3.0.0-alpha.7",
|
||||
"prettier": "^3.3.3",
|
||||
"pretty-format": "^29.3.1",
|
||||
"re-resizable": "^6.9.16",
|
||||
"react": "19.0.0-rc-77b637d6-20241016",
|
||||
"react-dom": "19.0.0-rc-77b637d6-20241016"
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.11.9",
|
||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"clsx": "^1.2.1",
|
||||
"concurrently": "^7.4.0",
|
||||
@@ -55,9 +55,5 @@
|
||||
"postcss": "^8.4.31",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"wait-on": "^7.2.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export default defineConfig({
|
||||
// Test directory
|
||||
testDir: path.join(__dirname, '__tests__/e2e'),
|
||||
// If a test fails, retry it additional 2 times
|
||||
retries: 2,
|
||||
retries: 3,
|
||||
// Artifacts folder where screenshots, videos, and traces are stored.
|
||||
outputDir: 'test-results/',
|
||||
// Note: we only use text snapshots, so its safe to omit the host environment name
|
||||
|
||||
@@ -23,6 +23,15 @@
|
||||
"@babel/highlight" "^7.24.7"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
"@babel/code-frame@^7.26.2":
|
||||
version "7.26.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
|
||||
integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
js-tokens "^4.0.0"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
"@babel/compat-data@^7.25.2":
|
||||
version "7.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb"
|
||||
@@ -59,6 +68,17 @@
|
||||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
jsesc "^2.5.1"
|
||||
|
||||
"@babel/generator@^7.26.10":
|
||||
version "7.26.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.10.tgz#a60d9de49caca16744e6340c3658dfef6138c3f7"
|
||||
integrity sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.26.10"
|
||||
"@babel/types" "^7.26.10"
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.25"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz#5373c7bc8366b12a033b4be1ac13a206c6656aab"
|
||||
@@ -66,6 +86,13 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4"
|
||||
integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.25.2":
|
||||
version "7.25.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c"
|
||||
@@ -77,26 +104,26 @@
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.25.0":
|
||||
version "7.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz#57eaf1af38be4224a9d9dd01ddde05b741f50e14"
|
||||
integrity sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==
|
||||
"@babel/helper-create-class-features-plugin@^7.25.9":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz#d6f83e3039547fbb39967e78043cd3c8b7820c71"
|
||||
integrity sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.24.7"
|
||||
"@babel/helper-member-expression-to-functions" "^7.24.8"
|
||||
"@babel/helper-optimise-call-expression" "^7.24.7"
|
||||
"@babel/helper-replace-supers" "^7.25.0"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.24.7"
|
||||
"@babel/traverse" "^7.25.4"
|
||||
"@babel/helper-annotate-as-pure" "^7.25.9"
|
||||
"@babel/helper-member-expression-to-functions" "^7.25.9"
|
||||
"@babel/helper-optimise-call-expression" "^7.25.9"
|
||||
"@babel/helper-replace-supers" "^7.26.5"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
|
||||
"@babel/traverse" "^7.26.9"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz#6155e079c913357d24a4c20480db7c712a5c3fb6"
|
||||
integrity sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==
|
||||
"@babel/helper-member-expression-to-functions@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz#9dfffe46f727005a5ea29051ac835fb735e4c1a3"
|
||||
integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.24.8"
|
||||
"@babel/types" "^7.24.8"
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-module-imports@^7.24.7":
|
||||
version "7.24.7"
|
||||
@@ -106,6 +133,14 @@
|
||||
"@babel/traverse" "^7.24.7"
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-module-imports@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715"
|
||||
integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-module-transforms@^7.24.8", "@babel/helper-module-transforms@^7.25.2":
|
||||
version "7.25.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6"
|
||||
@@ -116,26 +151,40 @@
|
||||
"@babel/helper-validator-identifier" "^7.24.7"
|
||||
"@babel/traverse" "^7.25.2"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz#8b0a0456c92f6b323d27cfd00d1d664e76692a0f"
|
||||
integrity sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==
|
||||
"@babel/helper-module-transforms@^7.26.0":
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae"
|
||||
integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.24.7"
|
||||
"@babel/helper-module-imports" "^7.25.9"
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
"@babel/traverse" "^7.25.9"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz#3324ae50bae7e2ab3c33f60c9a877b6a0146b54e"
|
||||
integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878"
|
||||
integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==
|
||||
|
||||
"@babel/helper-replace-supers@^7.25.0":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz#ff44deac1c9f619523fe2ca1fd650773792000a9"
|
||||
integrity sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==
|
||||
"@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5":
|
||||
version "7.26.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35"
|
||||
integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==
|
||||
|
||||
"@babel/helper-replace-supers@^7.26.5":
|
||||
version "7.26.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz#6cb04e82ae291dae8e72335dfe438b0725f14c8d"
|
||||
integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==
|
||||
dependencies:
|
||||
"@babel/helper-member-expression-to-functions" "^7.24.8"
|
||||
"@babel/helper-optimise-call-expression" "^7.24.7"
|
||||
"@babel/traverse" "^7.25.0"
|
||||
"@babel/helper-member-expression-to-functions" "^7.25.9"
|
||||
"@babel/helper-optimise-call-expression" "^7.25.9"
|
||||
"@babel/traverse" "^7.26.5"
|
||||
|
||||
"@babel/helper-simple-access@^7.24.7":
|
||||
version "7.24.7"
|
||||
@@ -145,29 +194,39 @@
|
||||
"@babel/traverse" "^7.24.7"
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@babel/helper-skip-transparent-expression-wrappers@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz#5f8fa83b69ed5c27adc56044f8be2b3ea96669d9"
|
||||
integrity sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==
|
||||
"@babel/helper-skip-transparent-expression-wrappers@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz#0b2e1b62d560d6b1954893fd2b705dc17c91f0c9"
|
||||
integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.24.7"
|
||||
"@babel/types" "^7.24.7"
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
|
||||
"@babel/helper-string-parser@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d"
|
||||
integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==
|
||||
"@babel/helper-string-parser@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
|
||||
integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.24.7":
|
||||
"@babel/helper-validator-identifier@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db"
|
||||
integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
|
||||
integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
|
||||
|
||||
"@babel/helper-validator-option@^7.24.7", "@babel/helper-validator-option@^7.24.8":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d"
|
||||
integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==
|
||||
|
||||
"@babel/helper-validator-option@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72"
|
||||
integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==
|
||||
|
||||
"@babel/helpers@^7.25.0":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60"
|
||||
@@ -193,6 +252,13 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.25.6"
|
||||
|
||||
"@babel/parser@^7.26.10", "@babel/parser@^7.26.9":
|
||||
version "7.26.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.10.tgz#e9bdb82f14b97df6569b0b038edd436839c57749"
|
||||
integrity sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.26.10"
|
||||
|
||||
"@babel/plugin-syntax-jsx@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d"
|
||||
@@ -200,13 +266,27 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.24.7"
|
||||
|
||||
"@babel/plugin-syntax-typescript@^7.18.9", "@babel/plugin-syntax-typescript@^7.24.7":
|
||||
"@babel/plugin-syntax-jsx@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290"
|
||||
integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.25.9"
|
||||
|
||||
"@babel/plugin-syntax-typescript@^7.18.9":
|
||||
version "7.25.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz#04db9ce5a9043d9c635e75ae7969a2cd50ca97ff"
|
||||
integrity sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.24.8"
|
||||
|
||||
"@babel/plugin-syntax-typescript@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399"
|
||||
integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.25.9"
|
||||
|
||||
"@babel/plugin-transform-block-scoping@^7.18.9":
|
||||
version "7.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz#23a6ed92e6b006d26b1869b1c91d1b917c2ea2ac"
|
||||
@@ -214,7 +294,7 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.24.8"
|
||||
|
||||
"@babel/plugin-transform-modules-commonjs@^7.18.9", "@babel/plugin-transform-modules-commonjs@^7.24.7":
|
||||
"@babel/plugin-transform-modules-commonjs@^7.18.9":
|
||||
version "7.24.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz#ab6421e564b717cb475d6fff70ae7f103536ea3c"
|
||||
integrity sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==
|
||||
@@ -223,6 +303,14 @@
|
||||
"@babel/helper-plugin-utils" "^7.24.8"
|
||||
"@babel/helper-simple-access" "^7.24.7"
|
||||
|
||||
"@babel/plugin-transform-modules-commonjs@^7.25.9":
|
||||
version "7.26.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz#8f011d44b20d02c3de44d8850d971d8497f981fb"
|
||||
integrity sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-transforms" "^7.26.0"
|
||||
"@babel/helper-plugin-utils" "^7.25.9"
|
||||
|
||||
"@babel/plugin-transform-react-display-name@^7.24.7":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz#9caff79836803bc666bcfe210aeb6626230c293b"
|
||||
@@ -256,16 +344,16 @@
|
||||
"@babel/helper-annotate-as-pure" "^7.24.7"
|
||||
"@babel/helper-plugin-utils" "^7.24.7"
|
||||
|
||||
"@babel/plugin-transform-typescript@^7.24.7":
|
||||
version "7.25.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz#237c5d10de6d493be31637c6b9fa30b6c5461add"
|
||||
integrity sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==
|
||||
"@babel/plugin-transform-typescript@^7.25.9":
|
||||
version "7.26.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz#2e9caa870aa102f50d7125240d9dbf91334b0950"
|
||||
integrity sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.24.7"
|
||||
"@babel/helper-create-class-features-plugin" "^7.25.0"
|
||||
"@babel/helper-plugin-utils" "^7.24.8"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.24.7"
|
||||
"@babel/plugin-syntax-typescript" "^7.24.7"
|
||||
"@babel/helper-annotate-as-pure" "^7.25.9"
|
||||
"@babel/helper-create-class-features-plugin" "^7.25.9"
|
||||
"@babel/helper-plugin-utils" "^7.26.5"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
|
||||
"@babel/plugin-syntax-typescript" "^7.25.9"
|
||||
|
||||
"@babel/preset-react@^7.18.9":
|
||||
version "7.24.7"
|
||||
@@ -279,16 +367,16 @@
|
||||
"@babel/plugin-transform-react-jsx-development" "^7.24.7"
|
||||
"@babel/plugin-transform-react-pure-annotations" "^7.24.7"
|
||||
|
||||
"@babel/preset-typescript@^7.18.9":
|
||||
version "7.24.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz#66cd86ea8f8c014855671d5ea9a737139cbbfef1"
|
||||
integrity sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==
|
||||
"@babel/preset-typescript@^7.26.0":
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz#4a570f1b8d104a242d923957ffa1eaff142a106d"
|
||||
integrity sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.24.7"
|
||||
"@babel/helper-validator-option" "^7.24.7"
|
||||
"@babel/plugin-syntax-jsx" "^7.24.7"
|
||||
"@babel/plugin-transform-modules-commonjs" "^7.24.7"
|
||||
"@babel/plugin-transform-typescript" "^7.24.7"
|
||||
"@babel/helper-plugin-utils" "^7.25.9"
|
||||
"@babel/helper-validator-option" "^7.25.9"
|
||||
"@babel/plugin-syntax-jsx" "^7.25.9"
|
||||
"@babel/plugin-transform-modules-commonjs" "^7.25.9"
|
||||
"@babel/plugin-transform-typescript" "^7.25.9"
|
||||
|
||||
"@babel/runtime@^7.21.0":
|
||||
version "7.25.6"
|
||||
@@ -306,7 +394,16 @@
|
||||
"@babel/parser" "^7.25.0"
|
||||
"@babel/types" "^7.25.0"
|
||||
|
||||
"@babel/traverse@^7.18.9", "@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.4":
|
||||
"@babel/template@^7.26.9":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.26.9.tgz#4577ad3ddf43d194528cff4e1fa6b232fa609bb2"
|
||||
integrity sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.26.2"
|
||||
"@babel/parser" "^7.26.9"
|
||||
"@babel/types" "^7.26.9"
|
||||
|
||||
"@babel/traverse@^7.18.9", "@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41"
|
||||
integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==
|
||||
@@ -319,22 +416,34 @@
|
||||
debug "^4.3.1"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@7.18.9":
|
||||
version "7.18.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f"
|
||||
integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==
|
||||
"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.9":
|
||||
version "7.26.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.10.tgz#43cca33d76005dbaa93024fae536cc1946a4c380"
|
||||
integrity sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.18.6"
|
||||
to-fast-properties "^2.0.0"
|
||||
"@babel/code-frame" "^7.26.2"
|
||||
"@babel/generator" "^7.26.10"
|
||||
"@babel/parser" "^7.26.10"
|
||||
"@babel/template" "^7.26.9"
|
||||
"@babel/types" "^7.26.10"
|
||||
debug "^4.3.1"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6"
|
||||
integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==
|
||||
"@babel/types@7.26.3", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6":
|
||||
version "7.26.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0"
|
||||
integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.24.8"
|
||||
"@babel/helper-validator-identifier" "^7.24.7"
|
||||
to-fast-properties "^2.0.0"
|
||||
"@babel/helper-string-parser" "^7.25.9"
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
|
||||
"@babel/types@^7.25.9", "@babel/types@^7.26.10", "@babel/types@^7.26.9":
|
||||
version "7.26.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.10.tgz#396382f6335bd4feb65741eacfc808218f859259"
|
||||
integrity sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.25.9"
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
|
||||
"@emnapi/runtime@^1.2.0":
|
||||
version "1.3.1"
|
||||
@@ -589,10 +698,10 @@
|
||||
dependencies:
|
||||
"@monaco-editor/loader" "^1.4.0"
|
||||
|
||||
"@next/env@15.0.1":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.0.1.tgz#660fe9303e255cec112d3f4198d2897a24bc60b3"
|
||||
integrity sha512-lc4HeDUKO9gxxlM5G2knTRifqhsY6yYpwuHspBZdboZe0Gp+rZHBNNSIjmQKDJIdRXiXGyVnSD6gafrbQPvILQ==
|
||||
"@next/env@15.2.0-canary.66":
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.2.0-canary.66.tgz#c4ca0d502ad099c68927643df9c9b5d75c7b7fbb"
|
||||
integrity sha512-/RxW1GJ7a6MJOQ7LOa2bcli7VTjqB7jPyzXwNJQflcYJH4gz1kP6uzg8+IptLJGFSRB58RBKHJk+q1cD8jongA==
|
||||
|
||||
"@next/eslint-plugin-next@15.0.1":
|
||||
version "15.0.1"
|
||||
@@ -601,45 +710,45 @@
|
||||
dependencies:
|
||||
fast-glob "3.3.1"
|
||||
|
||||
"@next/swc-darwin-arm64@15.0.1":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.1.tgz#b80a25f1569bd0ca03eca9473f7e93e64937e404"
|
||||
integrity sha512-C9k/Xv4sxkQRTA37Z6MzNq3Yb1BJMmSqjmwowoWEpbXTkAdfOwnoKOpAb71ItSzoA26yUTIo6ZhN8rKGu4ExQw==
|
||||
"@next/swc-darwin-arm64@15.2.0-canary.66":
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.2.0-canary.66.tgz#368438cf713c439b5b4c44d54b5c3b31ee5b772d"
|
||||
integrity sha512-sVzNJWTekcLOdqkDMistBGr84AVh9eSu4o5JQNEOdxHry4jiF8lqixpOg0+Twj2RRuv4bx32h5xaRVvCSUpITQ==
|
||||
|
||||
"@next/swc-darwin-x64@15.0.1":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.1.tgz#00dcf79ec7c638a85c3b9ff2e2de2bfb09c1c250"
|
||||
integrity sha512-uHl13HXOuq1G7ovWFxCACDJHTSDVbn/sbLv8V1p+7KIvTrYQ5HNoSmKBdYeEKRRCbEmd+OohOgg9YOp8Ux3MBg==
|
||||
"@next/swc-darwin-x64@15.2.0-canary.66":
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.2.0-canary.66.tgz#3ddc3f4f6e86e204727770e5984cabf52f852472"
|
||||
integrity sha512-Avv6Nf/0j0WVqY72Q0mK2glGhvN7LT7iVF31iBYUe/Cbf2cXBjgpXUVmksJjg+2Fi6uTEpaMoZWSVEpJyPkjVQ==
|
||||
|
||||
"@next/swc-linux-arm64-gnu@15.0.1":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.1.tgz#faab5f7ffcc6d1a15e8dea1cb9953966658b39bf"
|
||||
integrity sha512-LvyhvxHOihFTEIbb35KxOc3q8w8G4xAAAH/AQnsYDEnOvwawjL2eawsB59AX02ki6LJdgDaHoTEnC54Gw+82xw==
|
||||
"@next/swc-linux-arm64-gnu@15.2.0-canary.66":
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.2.0-canary.66.tgz#cd3683bf569c66444340b1e4d876913584e93aea"
|
||||
integrity sha512-kUPejaStjKpF79fz4525DKQKADtUuE+T6j7IvLQsZuWrSX3a5Mix+i52fdTzMJ+sFGg3v147wopZt6L6JMIxxA==
|
||||
|
||||
"@next/swc-linux-arm64-musl@15.0.1":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.1.tgz#97abada9a782ab5b3cb42cf0d4799cbc2e733351"
|
||||
integrity sha512-vFmCGUFNyk/A5/BYcQNhAQqPIw01RJaK6dRO+ZEhz0DncoW+hJW1kZ8aH2UvTX27zPq3m85zN5waMSbZEmANcQ==
|
||||
"@next/swc-linux-arm64-musl@15.2.0-canary.66":
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.2.0-canary.66.tgz#453836b11efdb50b91cf8a6cfbce8779f6778dd9"
|
||||
integrity sha512-U8l8jaZ+BAU5wn3bw7PRqq4vGTpObBt+7JbJLpbDqB1GfkZdCDc4nGtqAfLy3pY0O4lEfqal9jrsEVtUBCbfHg==
|
||||
|
||||
"@next/swc-linux-x64-gnu@15.0.1":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.1.tgz#548bd47c49fe6d819302139aff8766eb704322e2"
|
||||
integrity sha512-5by7IYq0NCF8rouz6Qg9T97jYU68kaClHPfGpQG2lCZpSYHtSPQF1kjnqBTd34RIqPKMbCa4DqCufirgr8HM5w==
|
||||
"@next/swc-linux-x64-gnu@15.2.0-canary.66":
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.2.0-canary.66.tgz#f02b295febaacf8d041f9f149c30c41aea16a81f"
|
||||
integrity sha512-c+AV8ZN1znGBHu5BACGym+9FhV8+213XVHFI7i2J7TSsJ6T+Eofhwn0tSn1Vy/XpVmpyoEdkwepL+djbdQAGhw==
|
||||
|
||||
"@next/swc-linux-x64-musl@15.0.1":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.1.tgz#84423fbd3a058dd6ae8322e530878f0ec7a1027a"
|
||||
integrity sha512-lmYr6H3JyDNBJLzklGXLfbehU3ay78a+b6UmBGlHls4xhDXBNZfgb0aI67sflrX+cGBnv1LgmWzFlYrAYxS1Qw==
|
||||
"@next/swc-linux-x64-musl@15.2.0-canary.66":
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.2.0-canary.66.tgz#f942c000ba3ffc0289520d25fa1067a75e72fa41"
|
||||
integrity sha512-4mTIv86qyXuo8NfjigSQ7rk2cDwM8/f8R/kf3hNh8NF1Aaat2RrEet9a/SbsuNpdhhNnPI5RcRwpIJx2JQSPcQ==
|
||||
|
||||
"@next/swc-win32-arm64-msvc@15.0.1":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.1.tgz#723c2ced12a998fb40dc901b8faea9170e788c2f"
|
||||
integrity sha512-DS8wQtl6diAj0eZTdH0sefykm4iXMbHT4MOvLwqZiIkeezKpkgPFcEdFlz3vKvXa2R/2UEgMh48z1nEpNhjeOQ==
|
||||
"@next/swc-win32-arm64-msvc@15.2.0-canary.66":
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.2.0-canary.66.tgz#0ffdcf5c74b5aa6214307f2ae4aa84f1526e6bf9"
|
||||
integrity sha512-NPnfsDQXk44h8VtncWq2AgLjHDbUMsc8Tpz7pcLe9qb8lZSxZ9jYbV7NwKzgd+qJbjy/58vgCWhL5PhyXDlWwQ==
|
||||
|
||||
"@next/swc-win32-x64-msvc@15.0.1":
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.1.tgz#ec7e3befc0bcc47527537b1eda2b3745beb15a09"
|
||||
integrity sha512-4Ho2ggvDdMKlZ/0e9HNdZ9ngeaBwtc+2VS5oCeqrbXqOgutX6I4U2X/42VBw0o+M5evn4/7v3zKgGHo+9v/VjA==
|
||||
"@next/swc-win32-x64-msvc@15.2.0-canary.66":
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.2.0-canary.66.tgz#458245850cf407d2551155e4662785c109f58bda"
|
||||
integrity sha512-L/ef++GJqW+T3g2x6mrZ2vrBK+6QS9Ieam8EqK9dG7cFKv7Gqm9yrHvDuVse62hnNB11ZdxfDDKrs9vabuQLlw==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
@@ -716,12 +825,12 @@
|
||||
resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
|
||||
integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
|
||||
|
||||
"@swc/helpers@0.5.13":
|
||||
version "0.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.13.tgz#33e63ff3cd0cade557672bd7888a39ce7d115a8c"
|
||||
integrity sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==
|
||||
"@swc/helpers@0.5.15":
|
||||
version "0.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.15.tgz#79efab344c5819ecf83a43f3f9f811fc84b516d7"
|
||||
integrity sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
tslib "^2.8.0"
|
||||
|
||||
"@types/json5@^0.0.29":
|
||||
version "0.0.29"
|
||||
@@ -733,17 +842,15 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4"
|
||||
integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==
|
||||
|
||||
"@types/react-dom@npm:types-react-dom@19.0.0-rc.1":
|
||||
version "19.0.0-rc.1"
|
||||
resolved "https://registry.yarnpkg.com/types-react-dom/-/types-react-dom-19.0.0-rc.1.tgz#1d544d02c5df2a82d87c2eff979afa2e21a8317a"
|
||||
integrity sha512-VSLZJl8VXCD0fAWp7DUTFUDCcZ8DVXOQmjhJMD03odgeFmu14ZQJHCXeETm3BEAhJqfgJaFkLnGkQv88sRx0fQ==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
"@types/react-dom@^19.0.0":
|
||||
version "19.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.4.tgz#bedba97f9346bd4c0fe5d39e689713804ec9ac89"
|
||||
integrity sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==
|
||||
|
||||
"@types/react@*", "@types/react@npm:types-react@19.0.0-rc.1":
|
||||
version "19.0.0-rc.1"
|
||||
resolved "https://registry.yarnpkg.com/types-react/-/types-react-19.0.0-rc.1.tgz#576d1a702f6d0cc5b24813a293913e5cbfeaa647"
|
||||
integrity sha512-RshndUfqTW6K3STLPis8BtAYCGOkMbtvYsi90gmVNDZBXUyUc5juf2PE9LfS/JmOlUIRO8cWTS/1MTnmhjDqyQ==
|
||||
"@types/react@^19.0.0":
|
||||
version "19.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.10.tgz#d0c66dafd862474190fe95ce11a68de69ed2b0eb"
|
||||
integrity sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==
|
||||
dependencies:
|
||||
csstype "^3.0.2"
|
||||
|
||||
@@ -2468,6 +2575,11 @@ jsesc@^2.5.1:
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
|
||||
|
||||
jsesc@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
|
||||
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
|
||||
|
||||
json-buffer@3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
|
||||
@@ -2682,27 +2794,27 @@ natural-compare@^1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
||||
|
||||
next@^15.0.1:
|
||||
version "15.0.1"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-15.0.1.tgz#a0e8eda35d803cb7f8092b2a2eb9d072e22bf21d"
|
||||
integrity sha512-PSkFkr/w7UnFWm+EP8y/QpHrJXMqpZzAXpergB/EqLPOh4SGPJXv1wj4mslr2hUZBAS9pX7/9YLIdxTv6fwytw==
|
||||
next@^15.2.0-canary.64:
|
||||
version "15.2.0-canary.66"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-15.2.0-canary.66.tgz#cb5ee4453c88f247b6e74fe33fd181eca58e7c86"
|
||||
integrity sha512-S+gsEu8vxxejI7nKqtCLqZlTi9L40xelLRK/Fgtvm/XT8W8ziLp3KMtN4I9Si5nEMU5uv7bllIfd04kVX8+HIw==
|
||||
dependencies:
|
||||
"@next/env" "15.0.1"
|
||||
"@next/env" "15.2.0-canary.66"
|
||||
"@swc/counter" "0.1.3"
|
||||
"@swc/helpers" "0.5.13"
|
||||
"@swc/helpers" "0.5.15"
|
||||
busboy "1.6.0"
|
||||
caniuse-lite "^1.0.30001579"
|
||||
postcss "8.4.31"
|
||||
styled-jsx "5.1.6"
|
||||
optionalDependencies:
|
||||
"@next/swc-darwin-arm64" "15.0.1"
|
||||
"@next/swc-darwin-x64" "15.0.1"
|
||||
"@next/swc-linux-arm64-gnu" "15.0.1"
|
||||
"@next/swc-linux-arm64-musl" "15.0.1"
|
||||
"@next/swc-linux-x64-gnu" "15.0.1"
|
||||
"@next/swc-linux-x64-musl" "15.0.1"
|
||||
"@next/swc-win32-arm64-msvc" "15.0.1"
|
||||
"@next/swc-win32-x64-msvc" "15.0.1"
|
||||
"@next/swc-darwin-arm64" "15.2.0-canary.66"
|
||||
"@next/swc-darwin-x64" "15.2.0-canary.66"
|
||||
"@next/swc-linux-arm64-gnu" "15.2.0-canary.66"
|
||||
"@next/swc-linux-arm64-musl" "15.2.0-canary.66"
|
||||
"@next/swc-linux-x64-gnu" "15.2.0-canary.66"
|
||||
"@next/swc-linux-x64-musl" "15.2.0-canary.66"
|
||||
"@next/swc-win32-arm64-msvc" "15.2.0-canary.66"
|
||||
"@next/swc-win32-x64-msvc" "15.2.0-canary.66"
|
||||
sharp "^0.33.5"
|
||||
|
||||
node-releases@^2.0.18:
|
||||
@@ -3025,12 +3137,12 @@ re-resizable@^6.9.16:
|
||||
resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.0.tgz#d684a096ab438f1a93f59ad3a580a206b0ce31ee"
|
||||
integrity sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw==
|
||||
|
||||
react-dom@19.0.0-rc-77b637d6-20241016:
|
||||
version "19.0.0-rc-77b637d6-20241016"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0-rc-77b637d6-20241016.tgz#71afcba4abbd81a73e85086029202423cf85355e"
|
||||
integrity sha512-xp5LvY+O6uvg0fNbSMyMXe0kbgzw6qn0mbqrdXStm4LBpFeMswLZ+XSNr+eJ0HyIiWrCw0rrXaVdqOxc9wtdKA==
|
||||
react-dom@^19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57"
|
||||
integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==
|
||||
dependencies:
|
||||
scheduler "0.25.0-rc-77b637d6-20241016"
|
||||
scheduler "^0.25.0"
|
||||
|
||||
react-is@^16.13.1:
|
||||
version "16.13.1"
|
||||
@@ -3042,10 +3154,10 @@ react-is@^18.0.0:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
|
||||
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
|
||||
|
||||
react@19.0.0-rc-77b637d6-20241016:
|
||||
version "19.0.0-rc-77b637d6-20241016"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0-rc-77b637d6-20241016.tgz#9e20f116d0195979f192537e00a0fa1687680319"
|
||||
integrity sha512-9A+i+PGSH/P4MezU4w38K9cbJuy0pzsXoPjPWIv6TQGCFmc5qCzC+8yce8dzfSEF1KJgCF2CLc5qtq/ePfiVqg==
|
||||
react@^19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
|
||||
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
|
||||
|
||||
read-cache@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -3167,10 +3279,10 @@ safe-regex-test@^1.0.3:
|
||||
es-errors "^1.3.0"
|
||||
is-regex "^1.1.4"
|
||||
|
||||
scheduler@0.25.0-rc-77b637d6-20241016:
|
||||
version "0.25.0-rc-77b637d6-20241016"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-rc-77b637d6-20241016.tgz#ab8f8d1cccc9668946caaa1103acdcdb5c871122"
|
||||
integrity sha512-R5NTrZXJaW4Dj2jHmad2MTehpFq4yUQOxRKDNV7clP1q4Pz6RtUIcofdPnGUWM0krlJAw8DHd/4jT41pFK4iEg==
|
||||
scheduler@^0.25.0:
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015"
|
||||
integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
|
||||
|
||||
semver@^6.3.1:
|
||||
version "6.3.1"
|
||||
@@ -3517,11 +3629,6 @@ thenify-all@^1.0.0:
|
||||
dependencies:
|
||||
any-promise "^1.0.0"
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||
@@ -3559,6 +3666,11 @@ tslib@^2.1.0, tslib@^2.4.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
|
||||
integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
|
||||
|
||||
tslib@^2.8.0:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||
|
||||
type-check@^0.4.0, type-check@~0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
[package]
|
||||
name = "react_build_hir"
|
||||
version = "0.1.0"
|
||||
publish = false
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
react_hir = { workspace = true }
|
||||
react_estree = { workspace = true}
|
||||
indexmap = { workspace = true }
|
||||
react_diagnostics = { workspace = true }
|
||||
react_semantic_analysis = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
@@ -1,3 +0,0 @@
|
||||
# Build-HIR
|
||||
|
||||
This crate converts from `react_estree` into React Compiler's HIR format as the first phase of compilation.
|
||||
@@ -1,746 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use react_diagnostics::Diagnostic;
|
||||
use react_estree::{
|
||||
AssignmentPropertyOrRestElement, AssignmentTarget, BlockStatement, Expression,
|
||||
ExpressionOrSpread, ExpressionOrSuper, ForInit, Function, IntoFunction, JsValue, Pattern,
|
||||
Statement, VariableDeclaration, VariableDeclarationKind,
|
||||
};
|
||||
use react_hir::{
|
||||
ArrayDestructureItem, BlockKind, BranchTerminal, Destructure, DestructurePattern, Environment,
|
||||
ForTerminal, GotoKind, Identifier, IdentifierOperand, InstructionKind, InstructionValue,
|
||||
JSXAttribute, JSXElement, LValue, LoadGlobal, LoadLocal, ObjectDestructureItem,
|
||||
ObjectDestructureProperty, PlaceOrSpread, TerminalValue,
|
||||
};
|
||||
|
||||
use crate::builder::{Builder, LoopScope};
|
||||
use crate::context::get_context_identifiers;
|
||||
use crate::error::BuildHIRError;
|
||||
|
||||
/// Converts a React function in ESTree format into HIR. Returns the HIR
|
||||
/// if it was constructed sucessfully, otherwise a list of diagnostics
|
||||
/// if the input could be not be converted to HIR.
|
||||
///
|
||||
/// Failures generally include nonsensical input (`delete 1`) or syntax
|
||||
/// that is not yet supported.
|
||||
pub fn build(env: &Environment, fun: &Function) -> Result<Box<react_hir::Function>, Diagnostic> {
|
||||
let mut builder = Builder::new(env);
|
||||
|
||||
let mut params = Vec::with_capacity(fun.params.len());
|
||||
for param in &fun.params {
|
||||
match param {
|
||||
Pattern::Identifier(param) => {
|
||||
let identifier = lower_identifier_for_assignment(
|
||||
env,
|
||||
&mut builder,
|
||||
InstructionKind::Let,
|
||||
param,
|
||||
)?;
|
||||
params.push(identifier);
|
||||
}
|
||||
_ => {
|
||||
return Err(Diagnostic::todo(
|
||||
"Support non-identifier params",
|
||||
param.range(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match &fun.body {
|
||||
Some(react_estree::FunctionBody::BlockStatement(body)) => {
|
||||
lower_block_statement(env, &mut builder, body)?
|
||||
}
|
||||
Some(react_estree::FunctionBody::Expression(body)) => {
|
||||
lower_expression(env, &mut builder, body)?;
|
||||
}
|
||||
None => {
|
||||
return Err(Diagnostic::invalid_syntax(
|
||||
BuildHIRError::EmptyFunction,
|
||||
fun.range,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// In case the function did not explicitly return, terminate the final
|
||||
// block with an explicit `return undefined`. If the function *did* return,
|
||||
// this will be unreachable and get pruned later.
|
||||
let implicit_return_value = builder.push(InstructionValue::Primitive(react_hir::Primitive {
|
||||
value: JsValue::Undefined,
|
||||
}));
|
||||
builder.terminate(
|
||||
TerminalValue::Return(react_hir::ReturnTerminal {
|
||||
value: implicit_return_value,
|
||||
}),
|
||||
react_hir::BlockKind::Block,
|
||||
);
|
||||
|
||||
let body = builder.build()?;
|
||||
Ok(Box::new(react_hir::Function {
|
||||
id: fun.id.as_ref().map(|id| id.name.clone()),
|
||||
body,
|
||||
params,
|
||||
// TODO: populate context!
|
||||
context: Default::default(),
|
||||
is_async: fun.is_async,
|
||||
is_generator: fun.is_generator,
|
||||
}))
|
||||
}
|
||||
|
||||
fn lower_block_statement(
|
||||
env: &Environment,
|
||||
builder: &mut Builder,
|
||||
stmt: &BlockStatement,
|
||||
) -> Result<(), Diagnostic> {
|
||||
for stmt in &stmt.body {
|
||||
lower_statement(env, builder, stmt, None)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Convert a statement to HIR. This will often result in multiple instructions and blocks
|
||||
/// being created as statements often describe control flow.
|
||||
fn lower_statement(
|
||||
env: &Environment,
|
||||
builder: &mut Builder,
|
||||
stmt: &Statement,
|
||||
label: Option<String>,
|
||||
) -> Result<(), Diagnostic> {
|
||||
match stmt {
|
||||
Statement::BlockStatement(stmt) => {
|
||||
lower_block_statement(env, builder, stmt)?;
|
||||
}
|
||||
Statement::BreakStatement(stmt) => {
|
||||
let block = builder.resolve_break(stmt.label.as_ref())?;
|
||||
builder.terminate(
|
||||
TerminalValue::Goto(react_hir::GotoTerminal {
|
||||
block,
|
||||
kind: GotoKind::Break,
|
||||
}),
|
||||
BlockKind::Block,
|
||||
);
|
||||
}
|
||||
Statement::ContinueStatement(stmt) => {
|
||||
let block = builder.resolve_continue(stmt.label.as_ref())?;
|
||||
builder.terminate(
|
||||
TerminalValue::Goto(react_hir::GotoTerminal {
|
||||
block,
|
||||
kind: GotoKind::Continue,
|
||||
}),
|
||||
BlockKind::Block,
|
||||
);
|
||||
}
|
||||
Statement::ReturnStatement(stmt) => {
|
||||
let value = match &stmt.argument {
|
||||
Some(argument) => lower_expression(env, builder, argument)?,
|
||||
None => builder.push(InstructionValue::Primitive(react_hir::Primitive {
|
||||
value: JsValue::Undefined,
|
||||
})),
|
||||
};
|
||||
builder.terminate(
|
||||
TerminalValue::Return(react_hir::ReturnTerminal { value }),
|
||||
BlockKind::Block,
|
||||
);
|
||||
}
|
||||
Statement::ExpressionStatement(stmt) => {
|
||||
lower_expression(env, builder, &stmt.expression)?;
|
||||
}
|
||||
Statement::EmptyStatement(_) => {
|
||||
// no-op
|
||||
}
|
||||
Statement::VariableDeclaration(stmt) => {
|
||||
lower_variable_declaration(env, builder, stmt)?;
|
||||
}
|
||||
Statement::IfStatement(stmt) => {
|
||||
// block for what follows the if statement, though this may
|
||||
// not be reachable
|
||||
let fallthrough_block = builder.reserve(BlockKind::Block);
|
||||
|
||||
let consequent_block = builder.enter(BlockKind::Block, |builder| {
|
||||
lower_statement(env, builder, &stmt.consequent, None)?;
|
||||
Ok(TerminalValue::Goto(react_hir::GotoTerminal {
|
||||
block: fallthrough_block.id,
|
||||
kind: GotoKind::Break,
|
||||
}))
|
||||
})?;
|
||||
|
||||
let alternate_block = builder.enter(BlockKind::Block, |builder| {
|
||||
if let Some(alternate) = &stmt.alternate {
|
||||
lower_statement(env, builder, alternate, None)?;
|
||||
}
|
||||
Ok(TerminalValue::Goto(react_hir::GotoTerminal {
|
||||
block: fallthrough_block.id,
|
||||
kind: GotoKind::Break,
|
||||
}))
|
||||
})?;
|
||||
|
||||
let test = lower_expression(env, builder, &stmt.test)?;
|
||||
let terminal = TerminalValue::If(react_hir::IfTerminal {
|
||||
test,
|
||||
consequent: consequent_block,
|
||||
alternate: alternate_block,
|
||||
fallthrough: Some(fallthrough_block.id),
|
||||
});
|
||||
builder.terminate_with_fallthrough(terminal, fallthrough_block);
|
||||
}
|
||||
Statement::ForStatement(stmt) => {
|
||||
// Block for the loop's test condition
|
||||
let test_block = builder.reserve(BlockKind::Loop);
|
||||
|
||||
// Block for code following the loop
|
||||
let fallthrough_block = builder.reserve(BlockKind::Block);
|
||||
|
||||
let init_block = builder.enter(BlockKind::Loop, |builder| {
|
||||
if let Some(ForInit::VariableDeclaration(decl)) = &stmt.init {
|
||||
lower_variable_declaration(env, builder, decl)?;
|
||||
Ok(TerminalValue::Goto(react_hir::GotoTerminal {
|
||||
block: test_block.id,
|
||||
kind: GotoKind::Break,
|
||||
}))
|
||||
} else {
|
||||
Err(Diagnostic::todo(
|
||||
BuildHIRError::ForStatementIsMissingInitializer,
|
||||
None,
|
||||
))
|
||||
}
|
||||
})?;
|
||||
|
||||
let update_block = stmt
|
||||
.update
|
||||
.as_ref()
|
||||
.map(|update| {
|
||||
builder.enter(BlockKind::Loop, |builder| {
|
||||
lower_expression(env, builder, update)?;
|
||||
Ok(TerminalValue::Goto(react_hir::GotoTerminal {
|
||||
block: test_block.id,
|
||||
kind: GotoKind::Break,
|
||||
}))
|
||||
})
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let body_block = builder.enter(BlockKind::Block, |builder| {
|
||||
let loop_ = LoopScope {
|
||||
label,
|
||||
continue_block: update_block.unwrap_or(test_block.id),
|
||||
break_block: fallthrough_block.id,
|
||||
};
|
||||
builder.enter_loop(loop_, |builder| {
|
||||
lower_statement(env, builder, &stmt.body, None)?;
|
||||
Ok(TerminalValue::Goto(react_hir::GotoTerminal {
|
||||
block: update_block.unwrap_or(test_block.id),
|
||||
kind: GotoKind::Continue,
|
||||
}))
|
||||
})
|
||||
})?;
|
||||
|
||||
let terminal = TerminalValue::For(ForTerminal {
|
||||
body: body_block,
|
||||
init: init_block,
|
||||
test: test_block.id,
|
||||
fallthrough: fallthrough_block.id,
|
||||
update: update_block,
|
||||
});
|
||||
builder.terminate_with_fallthrough(terminal, test_block);
|
||||
|
||||
if let Some(test) = &stmt.test {
|
||||
let test_value = lower_expression(env, builder, test)?;
|
||||
let terminal = TerminalValue::Branch(BranchTerminal {
|
||||
test: test_value,
|
||||
consequent: body_block,
|
||||
alternate: fallthrough_block.id,
|
||||
});
|
||||
builder.terminate_with_fallthrough(terminal, fallthrough_block);
|
||||
} else {
|
||||
return Err(Diagnostic::todo(
|
||||
BuildHIRError::ForStatementIsMissingTest,
|
||||
stmt.range,
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => todo!("Lower {stmt:#?}"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lower_variable_declaration(
|
||||
env: &Environment,
|
||||
builder: &mut Builder,
|
||||
stmt: &VariableDeclaration,
|
||||
) -> Result<(), Diagnostic> {
|
||||
let kind = match stmt.kind {
|
||||
VariableDeclarationKind::Const => InstructionKind::Const,
|
||||
VariableDeclarationKind::Let => InstructionKind::Let,
|
||||
VariableDeclarationKind::Var => {
|
||||
return Err(Diagnostic::unsupported(
|
||||
BuildHIRError::VariableDeclarationKindIsVar,
|
||||
stmt.range,
|
||||
));
|
||||
}
|
||||
};
|
||||
for declaration in &stmt.declarations {
|
||||
if let Some(init) = &declaration.init {
|
||||
let value = lower_expression(env, builder, init)?;
|
||||
lower_assignment_pattern(env, builder, kind, &declaration.id, value)?;
|
||||
} else {
|
||||
match &declaration.id {
|
||||
Pattern::Identifier(id) => {
|
||||
let identifier = env.resolve_variable_declaration(id.as_ref(), &id.name);
|
||||
if let Some(identifier) = identifier {
|
||||
builder.push(InstructionValue::DeclareLocal(react_hir::DeclareLocal {
|
||||
lvalue: LValue {
|
||||
identifier: IdentifierOperand {
|
||||
identifier,
|
||||
effect: None,
|
||||
},
|
||||
kind,
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
return Err(Diagnostic::invariant(
|
||||
BuildHIRError::VariableDeclarationBindingIsNonLocal,
|
||||
id.range,
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(Diagnostic::invalid_syntax(
|
||||
"Expected an identifier for variable declaration without an intializer. Destructuring requires an initial value",
|
||||
declaration.range,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Converts an ESTree Expression into an HIR InstructionValue. Note that while only a single
|
||||
/// InstructionValue is returned, this function is recursive and may cause multiple instructions
|
||||
/// to be emitted, possibly across multiple basic blocks (in the case of expressions with control
|
||||
/// flow semenatics such as logical, conditional, and optional expressions).
|
||||
fn lower_expression(
|
||||
env: &Environment,
|
||||
builder: &mut Builder,
|
||||
expr: &Expression,
|
||||
) -> Result<IdentifierOperand, Diagnostic> {
|
||||
let value = match expr {
|
||||
Expression::Identifier(expr) => {
|
||||
let identifier = env.resolve_variable_reference(expr.as_ref());
|
||||
if let Some(identifier) = identifier {
|
||||
let place = IdentifierOperand {
|
||||
effect: None,
|
||||
identifier,
|
||||
};
|
||||
InstructionValue::LoadLocal(LoadLocal { place })
|
||||
} else {
|
||||
InstructionValue::LoadGlobal(LoadGlobal {
|
||||
name: expr.name.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
Expression::Literal(expr) => InstructionValue::Primitive(react_hir::Primitive {
|
||||
value: expr.value.clone(),
|
||||
}),
|
||||
Expression::NumericLiteral(expr) => InstructionValue::Primitive(react_hir::Primitive {
|
||||
value: JsValue::Number(expr.value),
|
||||
}),
|
||||
Expression::BooleanLiteral(expr) => InstructionValue::Primitive(react_hir::Primitive {
|
||||
value: JsValue::Boolean(expr.value),
|
||||
}),
|
||||
Expression::StringLiteral(expr) => InstructionValue::Primitive(react_hir::Primitive {
|
||||
value: JsValue::String(expr.value.clone()),
|
||||
}),
|
||||
Expression::NullLiteral(_expr) => InstructionValue::Primitive(react_hir::Primitive {
|
||||
value: JsValue::Null,
|
||||
}),
|
||||
Expression::ArrayExpression(expr) => {
|
||||
let mut elements = Vec::with_capacity(expr.elements.len());
|
||||
for expr in &expr.elements {
|
||||
let element = match expr {
|
||||
Some(react_estree::ExpressionOrSpread::SpreadElement(expr)) => Some(
|
||||
PlaceOrSpread::Spread(lower_expression(env, builder, &expr.argument)?),
|
||||
),
|
||||
Some(react_estree::ExpressionOrSpread::Expression(expr)) => {
|
||||
Some(PlaceOrSpread::Place(lower_expression(env, builder, expr)?))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
elements.push(element);
|
||||
}
|
||||
InstructionValue::Array(react_hir::Array { elements })
|
||||
}
|
||||
|
||||
Expression::AssignmentExpression(expr) => match expr.operator {
|
||||
react_estree::AssignmentOperator::Equals => {
|
||||
let right = lower_expression(env, builder, &expr.right)?;
|
||||
return lower_assignment(
|
||||
env,
|
||||
builder,
|
||||
InstructionKind::Reassign,
|
||||
&expr.left,
|
||||
right,
|
||||
);
|
||||
}
|
||||
_ => todo!("lower assignment expr {:#?}", expr),
|
||||
},
|
||||
|
||||
Expression::BinaryExpression(expr) => {
|
||||
let left = lower_expression(env, builder, &expr.left)?;
|
||||
let right = lower_expression(env, builder, &expr.right)?;
|
||||
InstructionValue::Binary(react_hir::Binary {
|
||||
left,
|
||||
operator: expr.operator,
|
||||
right,
|
||||
})
|
||||
}
|
||||
|
||||
Expression::FunctionExpression(expr) => {
|
||||
InstructionValue::Function(lower_function(env, builder, expr.as_ref())?)
|
||||
}
|
||||
|
||||
Expression::ArrowFunctionExpression(expr) => {
|
||||
InstructionValue::Function(lower_function(env, builder, expr.as_ref())?)
|
||||
}
|
||||
|
||||
Expression::CallExpression(expr) => {
|
||||
let callee_expr = match &expr.callee {
|
||||
ExpressionOrSuper::Super(callee) => {
|
||||
return Err(Diagnostic::unsupported(
|
||||
BuildHIRError::UnsupportedSuperExpression,
|
||||
callee.range,
|
||||
));
|
||||
}
|
||||
ExpressionOrSuper::Expression(callee) => callee,
|
||||
};
|
||||
|
||||
if matches!(&callee_expr, Expression::MemberExpression(_)) {
|
||||
return Err(Diagnostic::todo("Support method calls", expr.range));
|
||||
}
|
||||
|
||||
let callee = lower_expression(env, builder, callee_expr)?;
|
||||
let arguments = lower_arguments(env, builder, &expr.arguments)?;
|
||||
InstructionValue::Call(react_hir::Call { callee, arguments })
|
||||
}
|
||||
|
||||
Expression::JSXElement(expr) => {
|
||||
InstructionValue::JSXElement(lower_jsx_element(env, builder, expr)?)
|
||||
}
|
||||
|
||||
_ => todo!("Lower expr {expr:#?}"),
|
||||
};
|
||||
Ok(builder.push(value))
|
||||
}
|
||||
|
||||
fn lower_arguments(
|
||||
env: &Environment,
|
||||
builder: &mut Builder,
|
||||
args: &[ExpressionOrSpread],
|
||||
) -> Result<Vec<PlaceOrSpread>, Diagnostic> {
|
||||
let mut arguments = Vec::with_capacity(args.len());
|
||||
for arg in args {
|
||||
let element = match arg {
|
||||
react_estree::ExpressionOrSpread::SpreadElement(arg) => {
|
||||
PlaceOrSpread::Spread(lower_expression(env, builder, &arg.argument)?)
|
||||
}
|
||||
react_estree::ExpressionOrSpread::Expression(arg) => {
|
||||
PlaceOrSpread::Place(lower_expression(env, builder, arg)?)
|
||||
}
|
||||
};
|
||||
arguments.push(element);
|
||||
}
|
||||
Ok(arguments)
|
||||
}
|
||||
|
||||
fn lower_function<T: IntoFunction>(
|
||||
env: &Environment,
|
||||
_builder: &mut Builder,
|
||||
function: &T,
|
||||
) -> Result<react_hir::FunctionExpression, Diagnostic> {
|
||||
let context_identifiers = get_context_identifiers(env, function);
|
||||
let mut context = Vec::new();
|
||||
let mut seen = HashSet::new();
|
||||
for declaration_id in context_identifiers {
|
||||
if let Some(identifier) = env.resolve_declaration_id(declaration_id) {
|
||||
if !seen.insert(identifier.id) {
|
||||
continue;
|
||||
}
|
||||
context.push(IdentifierOperand {
|
||||
effect: None,
|
||||
identifier,
|
||||
});
|
||||
}
|
||||
}
|
||||
let mut fun = build(env, function.function())?;
|
||||
fun.context = context;
|
||||
Ok(react_hir::FunctionExpression {
|
||||
// TODO: collect dependencies!
|
||||
dependencies: Default::default(),
|
||||
lowered_function: fun,
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_jsx_element(
|
||||
env: &Environment,
|
||||
builder: &mut Builder,
|
||||
expr: &react_estree::JSXElement,
|
||||
) -> Result<JSXElement, Diagnostic> {
|
||||
let props: Result<Vec<JSXAttribute>, Diagnostic> = expr
|
||||
.opening_element
|
||||
.attributes
|
||||
.iter()
|
||||
.map(|attr| lower_jsx_attribute(env, builder, attr))
|
||||
.collect();
|
||||
let _props = props?;
|
||||
let children: Result<Vec<IdentifierOperand>, Diagnostic> = expr
|
||||
.children
|
||||
.iter()
|
||||
.map(|child| {
|
||||
let child = lower_jsx_child(env, builder, child)?;
|
||||
Ok(child)
|
||||
})
|
||||
.collect();
|
||||
let _children = children?;
|
||||
todo!("lower jsx element");
|
||||
// Ok(JSXElement {
|
||||
// tag: todo!(),
|
||||
// props,
|
||||
// children: if children.is_empty() {
|
||||
// None
|
||||
// } else {
|
||||
// Some(children)
|
||||
// },
|
||||
// })
|
||||
}
|
||||
|
||||
fn lower_jsx_attribute(
|
||||
_env: &Environment,
|
||||
_builder: &mut Builder,
|
||||
_attr: &react_estree::JSXAttributeOrSpread,
|
||||
) -> Result<JSXAttribute, Diagnostic> {
|
||||
todo!("lower jsx attribute")
|
||||
}
|
||||
|
||||
fn lower_jsx_child(
|
||||
_env: &Environment,
|
||||
_builder: &mut Builder,
|
||||
_child: &react_estree::JSXChildItem,
|
||||
) -> Result<IdentifierOperand, Diagnostic> {
|
||||
todo!("lower jsx child")
|
||||
}
|
||||
|
||||
fn lower_assignment(
|
||||
env: &Environment,
|
||||
builder: &mut Builder,
|
||||
kind: InstructionKind,
|
||||
lvalue: &AssignmentTarget,
|
||||
value: IdentifierOperand,
|
||||
) -> Result<IdentifierOperand, Diagnostic> {
|
||||
Ok(match lvalue {
|
||||
AssignmentTarget::Pattern(lvalue) => {
|
||||
lower_assignment_pattern(env, builder, kind, lvalue, value)?
|
||||
}
|
||||
_ => todo!("lower assignment for {:#?}", lvalue),
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: change the success type to void, no caller uses it
|
||||
fn lower_assignment_pattern(
|
||||
env: &Environment,
|
||||
builder: &mut Builder,
|
||||
kind: InstructionKind,
|
||||
lvalue: &Pattern,
|
||||
value: IdentifierOperand,
|
||||
) -> Result<IdentifierOperand, Diagnostic> {
|
||||
Ok(match lvalue {
|
||||
Pattern::Identifier(lvalue) => {
|
||||
let identifier = lower_identifier_for_assignment(env, builder, kind, lvalue)?;
|
||||
builder.push(InstructionValue::StoreLocal(react_hir::StoreLocal {
|
||||
lvalue: LValue { identifier, kind },
|
||||
value,
|
||||
}))
|
||||
}
|
||||
Pattern::ArrayPattern(lvalue) => {
|
||||
let mut items = Vec::with_capacity(lvalue.elements.len());
|
||||
let mut followups: Vec<(Identifier, &Pattern)> = Vec::new();
|
||||
for element in &lvalue.elements {
|
||||
match element {
|
||||
None => items.push(ArrayDestructureItem::Hole),
|
||||
Some(Pattern::Identifier(element)) => {
|
||||
let identifier =
|
||||
lower_identifier_for_assignment(env, builder, kind, element)?;
|
||||
items.push(ArrayDestructureItem::Value(identifier));
|
||||
}
|
||||
Some(Pattern::RestElement(element)) => {
|
||||
if let Pattern::Identifier(element) = &element.argument {
|
||||
let identifier = lower_identifier_for_assignment(
|
||||
env,
|
||||
builder,
|
||||
kind,
|
||||
element.as_ref(),
|
||||
)?;
|
||||
items.push(ArrayDestructureItem::Spread(identifier));
|
||||
} else {
|
||||
let temporary = env.new_temporary();
|
||||
items.push(ArrayDestructureItem::Spread(IdentifierOperand {
|
||||
identifier: temporary.clone(),
|
||||
effect: None,
|
||||
}));
|
||||
followups.push((temporary, &element.argument));
|
||||
}
|
||||
}
|
||||
Some(element) => {
|
||||
let temporary = env.new_temporary();
|
||||
items.push(ArrayDestructureItem::Value(IdentifierOperand {
|
||||
identifier: temporary.clone(),
|
||||
effect: None,
|
||||
}));
|
||||
followups.push((temporary, element));
|
||||
}
|
||||
}
|
||||
}
|
||||
let temporary = builder.push(InstructionValue::Destructure(Destructure {
|
||||
kind,
|
||||
pattern: DestructurePattern::Array(items),
|
||||
value,
|
||||
}));
|
||||
for (temporary, pattern) in followups {
|
||||
lower_assignment_pattern(
|
||||
env,
|
||||
builder,
|
||||
kind,
|
||||
pattern,
|
||||
IdentifierOperand {
|
||||
identifier: temporary,
|
||||
effect: None,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
temporary
|
||||
}
|
||||
Pattern::ObjectPattern(lvalue) => {
|
||||
let mut properties = Vec::with_capacity(lvalue.properties.len());
|
||||
let mut followups: Vec<(Identifier, &Pattern)> = Vec::new();
|
||||
|
||||
for property in &lvalue.properties {
|
||||
match property {
|
||||
AssignmentPropertyOrRestElement::RestElement(property) => {
|
||||
if let Pattern::Identifier(element) = &property.argument {
|
||||
let identifier = lower_identifier_for_assignment(
|
||||
env,
|
||||
builder,
|
||||
kind,
|
||||
element.as_ref(),
|
||||
)?;
|
||||
properties.push(ObjectDestructureItem::Spread(identifier));
|
||||
} else {
|
||||
let temporary = env.new_temporary();
|
||||
properties.push(ObjectDestructureItem::Spread(IdentifierOperand {
|
||||
identifier: temporary.clone(),
|
||||
effect: None,
|
||||
}));
|
||||
followups.push((temporary, &property.argument));
|
||||
}
|
||||
}
|
||||
AssignmentPropertyOrRestElement::AssignmentProperty(property) => {
|
||||
if property.is_computed {
|
||||
return Err(Diagnostic::todo(
|
||||
"Handle computed properties in ObjectPattern",
|
||||
property.range,
|
||||
));
|
||||
}
|
||||
let key = if let Expression::Identifier(key) = &property.key {
|
||||
key.name.as_str()
|
||||
} else {
|
||||
return Err(Diagnostic::todo(
|
||||
"Support non-identifier object keys in non-computed ObjectPattern",
|
||||
property.range,
|
||||
));
|
||||
};
|
||||
if let Pattern::Identifier(value) = &property.value {
|
||||
let value = lower_identifier_for_assignment(env, builder, kind, value)?;
|
||||
properties.push(ObjectDestructureItem::Property(
|
||||
ObjectDestructureProperty {
|
||||
name: key.to_string(),
|
||||
value,
|
||||
},
|
||||
));
|
||||
} else {
|
||||
let temporary = env.new_temporary();
|
||||
properties.push(ObjectDestructureItem::Property(
|
||||
ObjectDestructureProperty {
|
||||
name: key.to_string(),
|
||||
value: IdentifierOperand {
|
||||
identifier: temporary.clone(),
|
||||
effect: None,
|
||||
},
|
||||
},
|
||||
));
|
||||
followups.push((temporary, &property.value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let temporary = builder.push(InstructionValue::Destructure(Destructure {
|
||||
kind,
|
||||
pattern: DestructurePattern::Object(properties),
|
||||
value,
|
||||
}));
|
||||
for (temporary, pattern) in followups {
|
||||
lower_assignment_pattern(
|
||||
env,
|
||||
builder,
|
||||
kind,
|
||||
pattern,
|
||||
IdentifierOperand {
|
||||
identifier: temporary,
|
||||
effect: None,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
temporary
|
||||
}
|
||||
_ => todo!("lower assignment pattern for {:#?}", lvalue),
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_identifier_for_assignment(
|
||||
env: &Environment,
|
||||
_builder: &mut Builder,
|
||||
kind: InstructionKind,
|
||||
node: &react_estree::Identifier,
|
||||
) -> Result<IdentifierOperand, Diagnostic> {
|
||||
match kind {
|
||||
InstructionKind::Reassign => {
|
||||
let identifier = env.resolve_variable_reference(node);
|
||||
if let Some(identifier) = identifier {
|
||||
Ok(IdentifierOperand {
|
||||
identifier,
|
||||
effect: None,
|
||||
})
|
||||
} else {
|
||||
// Reassigning a global
|
||||
Err(
|
||||
Diagnostic::invalid_react(BuildHIRError::ReassignedGlobal, node.range)
|
||||
.annotate(format!("Cannot reassign `{}`", &node.name), node.range),
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Declaration
|
||||
let identifier = env.resolve_variable_declaration(node, &node.name).unwrap();
|
||||
Ok(IdentifierOperand {
|
||||
identifier,
|
||||
effect: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use react_diagnostics::Diagnostic;
|
||||
use react_hir::{
|
||||
initialize_hir, BasicBlock, BlockId, BlockKind, Blocks, Environment, GotoKind, IdentifierData,
|
||||
IdentifierOperand, InstrIx, Instruction, InstructionIdGenerator, InstructionValue, Terminal,
|
||||
TerminalValue, Type, HIR,
|
||||
};
|
||||
|
||||
use crate::BuildHIRError;
|
||||
|
||||
/// Helper struct used when converting from ESTree to HIR. Includes:
|
||||
/// - Variable resolution
|
||||
/// - Label resolution (for labeled statements and break/continue)
|
||||
/// - Access to the environment
|
||||
///
|
||||
/// As well as representing the incomplete form of the HIR. Usage
|
||||
/// generally involves driving calls to enter/exit blocks, resolve
|
||||
/// labels and variables, and then calling `build()` when the HIR
|
||||
/// is complete.
|
||||
pub(crate) struct Builder<'e> {
|
||||
#[allow(dead_code)]
|
||||
environment: &'e Environment,
|
||||
|
||||
completed: Blocks,
|
||||
|
||||
instructions: Vec<Instruction>,
|
||||
|
||||
entry: BlockId,
|
||||
|
||||
wip: WipBlock,
|
||||
|
||||
id_gen: InstructionIdGenerator,
|
||||
|
||||
scopes: Vec<ControlFlowScope>,
|
||||
}
|
||||
|
||||
pub(crate) struct WipBlock {
|
||||
pub id: BlockId,
|
||||
pub kind: BlockKind,
|
||||
pub instructions: Vec<InstrIx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
enum ControlFlowScope {
|
||||
Loop(LoopScope),
|
||||
|
||||
// Switch(SwitchScope),
|
||||
#[allow(dead_code)]
|
||||
Label(LabelScope),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub(crate) struct LoopScope {
|
||||
pub label: Option<String>,
|
||||
pub continue_block: BlockId,
|
||||
pub break_block: BlockId,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub(crate) struct LabelScope {
|
||||
pub label: String,
|
||||
pub block: BlockId,
|
||||
}
|
||||
|
||||
impl ControlFlowScope {
|
||||
fn label(&self) -> Option<&String> {
|
||||
match self {
|
||||
Self::Loop(scope) => scope.label.as_ref(),
|
||||
Self::Label(scope) => Some(&scope.label),
|
||||
}
|
||||
}
|
||||
|
||||
fn break_block(&self) -> BlockId {
|
||||
match self {
|
||||
Self::Loop(scope) => scope.break_block,
|
||||
Self::Label(scope) => scope.block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'e> Builder<'e> {
|
||||
pub(crate) fn new(environment: &'e Environment) -> Self {
|
||||
let entry = environment.next_block_id();
|
||||
let current = WipBlock {
|
||||
id: entry,
|
||||
kind: BlockKind::Block,
|
||||
instructions: Default::default(),
|
||||
};
|
||||
Self {
|
||||
environment,
|
||||
completed: Default::default(),
|
||||
instructions: Default::default(),
|
||||
entry,
|
||||
wip: current,
|
||||
id_gen: InstructionIdGenerator::new(),
|
||||
scopes: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Completes the builder and returns the HIR if it was valid,
|
||||
/// or a Diagnostic if a validation error occured.
|
||||
///
|
||||
/// TODO: refine the type, only invariants should be possible here,
|
||||
/// not other types of errors
|
||||
pub(crate) fn build(self) -> Result<HIR, Diagnostic> {
|
||||
let mut hir = HIR {
|
||||
entry: self.entry,
|
||||
blocks: self.completed,
|
||||
instructions: self.instructions,
|
||||
};
|
||||
// Run all the initialization passes
|
||||
initialize_hir(&mut hir)?;
|
||||
Ok(hir)
|
||||
}
|
||||
|
||||
/// Adds a new instruction to the end of the work in progress block
|
||||
pub(crate) fn push(&mut self, value: InstructionValue) -> IdentifierOperand {
|
||||
let lvalue = IdentifierOperand {
|
||||
identifier: self.environment.new_temporary(),
|
||||
effect: None,
|
||||
};
|
||||
let instr = Instruction {
|
||||
id: self.id_gen.next(),
|
||||
lvalue: lvalue.clone(),
|
||||
value,
|
||||
};
|
||||
let ix = InstrIx::new(self.instructions.len() as u32);
|
||||
self.instructions.push(instr);
|
||||
self.wip.instructions.push(ix);
|
||||
lvalue
|
||||
}
|
||||
|
||||
/// Terminates the work in progress block with the given terminal, and starts a new
|
||||
/// work in progress block with the given kind
|
||||
pub(crate) fn terminate(&mut self, terminal: TerminalValue, next_kind: BlockKind) {
|
||||
let next_wip = WipBlock {
|
||||
id: self.environment.next_block_id(),
|
||||
kind: next_kind,
|
||||
instructions: Default::default(),
|
||||
};
|
||||
self.terminate_with_fallthrough(terminal, next_wip)
|
||||
}
|
||||
|
||||
pub(crate) fn terminate_with_fallthrough(
|
||||
&mut self,
|
||||
terminal: TerminalValue,
|
||||
fallthrough: WipBlock,
|
||||
) {
|
||||
let prev_wip = std::mem::replace(&mut self.wip, fallthrough);
|
||||
self.completed.insert(Box::new(BasicBlock {
|
||||
id: prev_wip.id,
|
||||
kind: prev_wip.kind,
|
||||
instructions: prev_wip.instructions,
|
||||
terminal: Terminal {
|
||||
id: self.id_gen.next(),
|
||||
value: terminal,
|
||||
},
|
||||
predecessors: Default::default(),
|
||||
phis: Default::default(),
|
||||
}));
|
||||
}
|
||||
|
||||
pub(crate) fn reserve(&mut self, kind: BlockKind) -> WipBlock {
|
||||
WipBlock {
|
||||
id: self.environment.next_block_id(),
|
||||
kind,
|
||||
instructions: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enter<F>(&mut self, kind: BlockKind, f: F) -> Result<BlockId, Diagnostic>
|
||||
where
|
||||
F: FnOnce(&mut Self) -> Result<TerminalValue, Diagnostic>,
|
||||
{
|
||||
let wip = self.reserve(kind);
|
||||
let id = wip.id;
|
||||
self.enter_reserved(wip, f)?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn enter_reserved<F>(&mut self, wip: WipBlock, f: F) -> Result<(), Diagnostic>
|
||||
where
|
||||
F: FnOnce(&mut Self) -> Result<TerminalValue, Diagnostic>,
|
||||
{
|
||||
let current = std::mem::replace(&mut self.wip, wip);
|
||||
|
||||
let (result, terminal) = match f(self) {
|
||||
Ok(terminal) => (Ok(()), terminal),
|
||||
Err(error) => (
|
||||
Err(error),
|
||||
// TODO: add a `Terminal::Error` variant
|
||||
TerminalValue::Goto(react_hir::GotoTerminal {
|
||||
block: current.id,
|
||||
kind: GotoKind::Break,
|
||||
}),
|
||||
),
|
||||
};
|
||||
|
||||
let completed = std::mem::replace(&mut self.wip, current);
|
||||
self.completed.insert(Box::new(BasicBlock {
|
||||
id: completed.id,
|
||||
kind: completed.kind,
|
||||
instructions: completed.instructions,
|
||||
terminal: Terminal {
|
||||
id: self.id_gen.next(),
|
||||
value: terminal,
|
||||
},
|
||||
predecessors: Default::default(),
|
||||
phis: Default::default(),
|
||||
}));
|
||||
result
|
||||
}
|
||||
|
||||
pub(crate) fn enter_loop<F>(
|
||||
&mut self,
|
||||
scope: LoopScope,
|
||||
f: F,
|
||||
) -> Result<TerminalValue, Diagnostic>
|
||||
where
|
||||
F: FnOnce(&mut Self) -> Result<TerminalValue, Diagnostic>,
|
||||
{
|
||||
self.scopes.push(ControlFlowScope::Loop(scope.clone()));
|
||||
let terminal = f(self);
|
||||
let last = self.scopes.pop().unwrap();
|
||||
assert_eq!(last, ControlFlowScope::Loop(scope));
|
||||
terminal
|
||||
}
|
||||
|
||||
/// Returns a new temporary identifier
|
||||
/// This may be necessary for destructuring with default values. there
|
||||
/// we synthesize a temporary identifier to store the possibly-missing value
|
||||
/// into, and emit a later StoreLocal for the original identifier
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn make_temporary(&self) -> react_hir::Identifier {
|
||||
react_hir::Identifier {
|
||||
id: self.environment.next_identifier_id(),
|
||||
name: None,
|
||||
data: Rc::new(RefCell::new(IdentifierData {
|
||||
mutable_range: Default::default(),
|
||||
scope: None,
|
||||
type_: Type::Var(self.environment.next_type_var_id()),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the target for the given break label (if present), or returns the default
|
||||
/// break target given the current context. Returns a diagnostic if the label is
|
||||
/// provided but cannot be resolved.
|
||||
pub(crate) fn resolve_break(
|
||||
&self,
|
||||
label: Option<&react_estree::Identifier>,
|
||||
) -> Result<BlockId, Diagnostic> {
|
||||
for scope in self.scopes.iter().rev() {
|
||||
match (label, scope.label()) {
|
||||
// If this is an unlabeled break, return the most recent break target
|
||||
(None, _) => return Ok(scope.break_block()),
|
||||
// If the break is labeled and matches the current scope, return its break target
|
||||
(Some(label), Some(scope_label)) if &label.name == scope_label => {
|
||||
return Ok(scope.break_block());
|
||||
}
|
||||
// Otherwise keep searching
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
Err(Diagnostic::invalid_syntax(
|
||||
BuildHIRError::UnresolvedBreakTarget,
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
||||
/// Resolves the target for the given continue label (if present), or returns the default
|
||||
/// continue target given the current context. Returns a diagnostic if the label is
|
||||
/// provided but cannot be resolved.
|
||||
pub(crate) fn resolve_continue(
|
||||
&self,
|
||||
label: Option<&react_estree::Identifier>,
|
||||
) -> Result<BlockId, Diagnostic> {
|
||||
for scope in self.scopes.iter().rev() {
|
||||
match scope {
|
||||
ControlFlowScope::Loop(scope) => {
|
||||
match (label, &scope.label) {
|
||||
// If this is an unlabeled continue, return the first matching loop
|
||||
(None, _) => return Ok(scope.continue_block),
|
||||
// If the continue is labeled and matches the current scope, return its continue target
|
||||
(Some(label), Some(scope_label))
|
||||
if label.name.as_str() == scope_label.as_str() =>
|
||||
{
|
||||
return Ok(scope.continue_block);
|
||||
}
|
||||
// Otherwise keep searching
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
match (label, scope.label()) {
|
||||
(Some(label), Some(scope_label)) if label.name.as_str() == scope_label => {
|
||||
// Error, the continue referred to a label that is not a loop
|
||||
return Err(Diagnostic::invalid_syntax(
|
||||
BuildHIRError::ContinueTargetIsNotALoop,
|
||||
None,
|
||||
));
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Diagnostic::invalid_syntax(
|
||||
BuildHIRError::UnresolvedContinueTarget,
|
||||
None,
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use react_estree::IntoFunction;
|
||||
use react_hir::Environment;
|
||||
use react_semantic_analysis::{DeclarationId, ScopeView};
|
||||
|
||||
pub(crate) fn get_context_identifiers<T: IntoFunction>(
|
||||
env: &Environment,
|
||||
node: &T,
|
||||
) -> Vec<DeclarationId> {
|
||||
let function_scope = env.scope(node.function()).unwrap();
|
||||
let mut free = FreeVariables::default();
|
||||
let mut seen = HashSet::new();
|
||||
populate_free_variable_references(&mut free, &mut seen, function_scope);
|
||||
free
|
||||
}
|
||||
|
||||
type FreeVariables = Vec<DeclarationId>;
|
||||
|
||||
fn populate_free_variable_references(
|
||||
free: &mut FreeVariables,
|
||||
seen: &mut HashSet<DeclarationId>,
|
||||
scope: ScopeView<'_>,
|
||||
) {
|
||||
for reference in scope.references() {
|
||||
if !seen.insert(reference.declaration().id()) {
|
||||
continue;
|
||||
}
|
||||
let declaration_scope = reference.declaration().scope();
|
||||
if !declaration_scope.is_descendant_of(scope) {
|
||||
free.push(reference.declaration().id())
|
||||
}
|
||||
}
|
||||
for child in scope.children() {
|
||||
populate_free_variable_references(free, seen, child);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors which can occur during HIR construction
|
||||
#[derive(Error, Debug)]
|
||||
pub enum BuildHIRError {
|
||||
/// ErrorSeverity::Unsupported
|
||||
#[error(
|
||||
"Variable declarations must be `let` or `const`, `var` declarations are not supported"
|
||||
)]
|
||||
VariableDeclarationKindIsVar,
|
||||
|
||||
/// ErrorSeverity::Invariant
|
||||
#[error("Invariant: Expected variable declaration to declare a fresh binding")]
|
||||
VariableDeclarationBindingIsNonLocal,
|
||||
|
||||
/// ErrorSeverity::Todo
|
||||
#[error("`for` statements must have an initializer, eg `for (**let i = 0**; ...)`")]
|
||||
ForStatementIsMissingInitializer,
|
||||
|
||||
/// ErrorSeverity::Todo
|
||||
#[error(
|
||||
"`for` statements must have a test condition, eg `for (let i = 0; **i < count**; ...)`"
|
||||
)]
|
||||
ForStatementIsMissingTest,
|
||||
|
||||
/// ErrorSeverity::Invariant
|
||||
#[error("Invariant: Expected an expression node")]
|
||||
NonExpressionInExpressionPosition,
|
||||
|
||||
/// ErrorSeverity::InvalidReact
|
||||
#[error("React functions may not reassign variables defined outside of the component or hook")]
|
||||
ReassignedGlobal,
|
||||
|
||||
/// ErrorSeverity::InvalidSyntax
|
||||
#[error("Could not resolve a target for `break` statement")]
|
||||
UnresolvedBreakTarget,
|
||||
|
||||
/// ErrorSeverity::InvalidSyntax
|
||||
#[error("Could not resolve a target for `continue` statement")]
|
||||
UnresolvedContinueTarget,
|
||||
|
||||
/// ErrorSeverity::InvalidSyntax
|
||||
#[error("Labeled `continue` statements must use the label of a loop statement")]
|
||||
ContinueTargetIsNotALoop,
|
||||
|
||||
/// ErrorSeverity::Invariant
|
||||
#[error("Invariant: Identifier was not resolved (did name resolution run successfully?)")]
|
||||
UnknownIdentifier,
|
||||
|
||||
/// ErrorSeverity::InvalidSyntax
|
||||
#[error("Expected function to have a body")]
|
||||
EmptyFunction,
|
||||
|
||||
#[error("`super` is not suppported")]
|
||||
UnsupportedSuperExpression,
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
mod build;
|
||||
mod builder;
|
||||
mod context;
|
||||
mod error;
|
||||
|
||||
pub use build::build;
|
||||
pub use error::*;
|
||||
@@ -1,23 +0,0 @@
|
||||
[package]
|
||||
name = "react_diagnostics"
|
||||
version = "0.1.0"
|
||||
publish = false
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
# TODO: extract SourceRange into a separate crate so that
|
||||
# we don't depend on full estree here
|
||||
react_estree = { workspace = true }
|
||||
# TODO: consider extracting a separate react_miette crate which does
|
||||
# the translation from react_diagnostics::Diagnostic to miette::Diagnostic
|
||||
miette = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
static_assertions = { workspace = true }
|
||||
@@ -1,10 +0,0 @@
|
||||
# react_diagnostics
|
||||
|
||||
Types for representing compiler diagnostics. Includes a general-purpose representation
|
||||
of diagnostics with related information which can be converted into `miette::Diagnostic` to exploit miette's pretty printing of errors.
|
||||
|
||||
Unlike miette, lsp_types, and other diagnostic libraries, the error severities match
|
||||
React Compiler's semantics. The intent is that a given diagnostic may be displayed as
|
||||
an error, warning, or not displayed at all depending on the context in which the
|
||||
compiler is being used. For example, an ESLint plugin powered by React Compiler may ignore
|
||||
InvalidSyntax diagnostics, whereas the regular compiler may report them as errors.
|
||||
@@ -1,285 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Write};
|
||||
|
||||
use miette::SourceSpan;
|
||||
use react_estree::SourceRange;
|
||||
use static_assertions::assert_impl_all;
|
||||
use thiserror::Error;
|
||||
|
||||
pub type Diagnostics = Vec<Diagnostic>;
|
||||
pub type DiagnosticsResult<T> = Result<T, Diagnostics>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WithDiagnostics<T> {
|
||||
pub item: T,
|
||||
pub diagnostics: Vec<Diagnostic>,
|
||||
}
|
||||
|
||||
impl<T> From<WithDiagnostics<T>> for Result<T, Diagnostics> {
|
||||
fn from(s: WithDiagnostics<T>) -> Result<T, Diagnostics> {
|
||||
if s.diagnostics.is_empty() {
|
||||
Ok(s.item)
|
||||
} else {
|
||||
Err(s.diagnostics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn diagnostics_result<T>(result: T, diagnostics: Diagnostics) -> DiagnosticsResult<T> {
|
||||
if diagnostics.is_empty() {
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Error)]
|
||||
pub enum DiagnosticSeverity {
|
||||
/// A feature that is intended to work but not yet implemented
|
||||
#[error("Not implemented")]
|
||||
Todo,
|
||||
|
||||
/// Syntax that is valid but intentionally not supported
|
||||
#[error("Unsupported")]
|
||||
Unsupported,
|
||||
|
||||
/// Invalid syntax
|
||||
#[error("Invalid JavaScript")]
|
||||
InvalidSyntax,
|
||||
|
||||
/// Valid syntax, but invalid React
|
||||
#[error("Invalid React")]
|
||||
InvalidReact,
|
||||
|
||||
/// Internal compiler error (ICE)
|
||||
#[error("Internal error")]
|
||||
Invariant,
|
||||
}
|
||||
|
||||
/// A diagnostic message as a result of validating some code. This struct is
|
||||
/// modeled after the LSP Diagnostic type:
|
||||
/// https://microsoft.github.io/language-server-protocol/specification#diagnostic
|
||||
///
|
||||
/// Changes from LSP:
|
||||
/// - `location` is different from LSP in that it's a file + span instead of
|
||||
/// just a span.
|
||||
/// - Unused fields are omitted.
|
||||
/// - Severity is a custom enum that represents React-specific categories of error.
|
||||
/// The translation to an LSP error/warning/etc depends on compiler settings and
|
||||
/// invocation context.
|
||||
#[derive(Debug)]
|
||||
pub struct Diagnostic(Box<DiagnosticData>);
|
||||
|
||||
impl Diagnostic {
|
||||
fn with_severity<T: 'static + DiagnosticDisplay>(
|
||||
severity: DiagnosticSeverity,
|
||||
message: T,
|
||||
range: Option<SourceRange>,
|
||||
) -> Self {
|
||||
Self(Box::new(DiagnosticData {
|
||||
message: Box::new(message),
|
||||
span: range.map(source_span_from_range),
|
||||
related_information: Vec::new(),
|
||||
severity,
|
||||
data: Vec::new(),
|
||||
}))
|
||||
}
|
||||
|
||||
/// Creates a new Todo Diagnostic.
|
||||
/// Additional locations can be added with the `.annotate()` function.
|
||||
pub fn todo<T: 'static + DiagnosticDisplay>(message: T, range: Option<SourceRange>) -> Self {
|
||||
Diagnostic::with_severity(DiagnosticSeverity::Todo, message, range)
|
||||
}
|
||||
|
||||
/// Creates a new Unsupported Diagnostic.
|
||||
/// Additional locations can be added with the `.annotate()` function.
|
||||
pub fn unsupported<T: 'static + DiagnosticDisplay>(
|
||||
message: T,
|
||||
range: Option<SourceRange>,
|
||||
) -> Self {
|
||||
Diagnostic::with_severity(DiagnosticSeverity::Unsupported, message, range)
|
||||
}
|
||||
|
||||
/// Creates a new InvalidSyntax Diagnostic.
|
||||
/// Additional locations can be added with the `.annotate()` function.
|
||||
pub fn invalid_syntax<T: 'static + DiagnosticDisplay>(
|
||||
message: T,
|
||||
range: Option<SourceRange>,
|
||||
) -> Self {
|
||||
Diagnostic::with_severity(DiagnosticSeverity::InvalidSyntax, message, range)
|
||||
}
|
||||
|
||||
/// Creates a new InvalidReact Diagnostic.
|
||||
/// Additional locations can be added with the `.annotate()` function.
|
||||
pub fn invalid_react<T: 'static + DiagnosticDisplay>(
|
||||
message: T,
|
||||
range: Option<SourceRange>,
|
||||
) -> Self {
|
||||
Diagnostic::with_severity(DiagnosticSeverity::InvalidReact, message, range)
|
||||
}
|
||||
|
||||
/// Creates a new InvalidReact Diagnostic.
|
||||
/// Additional locations can be added with the `.annotate()` function.
|
||||
pub fn invariant<T: 'static + DiagnosticDisplay>(
|
||||
message: T,
|
||||
range: Option<SourceRange>,
|
||||
) -> Self {
|
||||
Diagnostic::with_severity(DiagnosticSeverity::Invariant, message, range)
|
||||
}
|
||||
|
||||
/// Annotates this error with an additional location and associated message.
|
||||
pub fn annotate<T: 'static + DiagnosticDisplay>(
|
||||
mut self,
|
||||
message: T,
|
||||
range: Option<SourceRange>,
|
||||
) -> Self {
|
||||
self.0
|
||||
.related_information
|
||||
.push(DiagnosticRelatedInformation {
|
||||
message: Box::new(message),
|
||||
span: range.map(source_span_from_range),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn message(&self) -> &impl DiagnosticDisplay {
|
||||
&self.0.message
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Option<SourceSpan> {
|
||||
self.0.span
|
||||
}
|
||||
|
||||
pub fn get_data(&self) -> &[impl DiagnosticDisplay] {
|
||||
&self.0.data
|
||||
}
|
||||
|
||||
pub fn severity(&self) -> DiagnosticSeverity {
|
||||
self.0.severity
|
||||
}
|
||||
|
||||
pub fn related_information(&self) -> &[DiagnosticRelatedInformation] {
|
||||
&self.0.related_information
|
||||
}
|
||||
|
||||
pub fn print_without_source(&self) -> String {
|
||||
let mut result = String::new();
|
||||
writeln!(
|
||||
result,
|
||||
"{message}:{span:?}",
|
||||
message = &self.0.message,
|
||||
span = self.0.span
|
||||
)
|
||||
.unwrap();
|
||||
if !self.0.related_information.is_empty() {
|
||||
for (ix, related) in self.0.related_information.iter().enumerate() {
|
||||
writeln!(
|
||||
result,
|
||||
"[related {ix}] {message}:{span:?}",
|
||||
ix = ix + 1,
|
||||
message = related.message,
|
||||
span = related.span
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
};
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Diagnostic {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for Diagnostic {}
|
||||
|
||||
impl miette::Diagnostic for Diagnostic {
|
||||
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
Some(Box::new(self.0.message.to_string()))
|
||||
}
|
||||
|
||||
fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
|
||||
let related_items = &self.0.related_information;
|
||||
let mut spans: Vec<miette::LabeledSpan> = Vec::new();
|
||||
for related in related_items {
|
||||
if let Some(span) = related.span {
|
||||
spans.push(miette::LabeledSpan::new_with_span(
|
||||
Some(related.message.to_string()),
|
||||
span,
|
||||
))
|
||||
}
|
||||
}
|
||||
if spans.is_empty() {
|
||||
if let Some(span) = self.0.span {
|
||||
spans.push(miette::LabeledSpan::new_with_span(
|
||||
Some(self.0.message.to_string()),
|
||||
span,
|
||||
))
|
||||
}
|
||||
}
|
||||
Some(Box::new(spans.into_iter()))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure Diagnostic is thread-safe
|
||||
assert_impl_all!(Diagnostic: Send, Sync);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DiagnosticData {
|
||||
/// Human readable error message.
|
||||
message: Box<dyn DiagnosticDisplay>,
|
||||
|
||||
/// The primary location of this diagnostic.
|
||||
span: Option<SourceSpan>,
|
||||
|
||||
/// Related diagnostic information, such as other definitions in the case of
|
||||
/// a duplicate definition error.
|
||||
related_information: Vec<DiagnosticRelatedInformation>,
|
||||
|
||||
severity: DiagnosticSeverity,
|
||||
|
||||
/// A list with data that can be passed to the code actions
|
||||
/// `data` is used in the LSP protocol:
|
||||
/// @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
|
||||
data: Vec<Box<dyn DiagnosticDisplay>>,
|
||||
}
|
||||
|
||||
/// Secondary locations attached to a diagnostic.
|
||||
#[derive(Debug)]
|
||||
pub struct DiagnosticRelatedInformation {
|
||||
/// The message of this related diagnostic information.
|
||||
pub message: Box<dyn DiagnosticDisplay>,
|
||||
|
||||
/// The location of this related diagnostic information.
|
||||
pub span: Option<SourceSpan>,
|
||||
}
|
||||
|
||||
/// Trait for diagnostic messages to allow structs that capture
|
||||
/// some data and can lazily convert it to a message.
|
||||
pub trait DiagnosticDisplay: Debug + Display + Send + Sync {}
|
||||
|
||||
/// Automatically implement the trait if constraints are met, so that
|
||||
/// implementors don't need to.
|
||||
impl<T> DiagnosticDisplay for T where T: Debug + Display + Send + Sync {}
|
||||
|
||||
impl From<Diagnostic> for Diagnostics {
|
||||
fn from(diagnostic: Diagnostic) -> Self {
|
||||
vec![diagnostic]
|
||||
}
|
||||
}
|
||||
|
||||
fn source_span_from_range(range: SourceRange) -> SourceSpan {
|
||||
SourceSpan::new(
|
||||
(range.start as usize).into(),
|
||||
((u32::from(range.end) - range.start) as usize).into(),
|
||||
)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
mod diagnostic;
|
||||
|
||||
pub use diagnostic::*;
|
||||
|
||||
/// Returns Ok(()) if the condition is true, otherwise returns Err()
|
||||
/// with the diagnostic produced by the provided callback
|
||||
pub fn invariant<F>(cond: bool, f: F) -> Result<(), Diagnostic>
|
||||
where
|
||||
F: Fn() -> Diagnostic,
|
||||
{
|
||||
if cond { Ok(()) } else { Err(f()) }
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
[package]
|
||||
name = "react_estree"
|
||||
version = "0.1.0"
|
||||
publish = false
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
insta = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
static_assertions = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
react_estree_codegen = { workspace = true }
|
||||
@@ -1,17 +0,0 @@
|
||||
# react_estree
|
||||
|
||||
This crate is a Rust representation of the [ESTree format](https://github.com/estree/estree/tree/master) and
|
||||
popular extenions including JSX and (eventually) Flow and TypeScript.
|
||||
|
||||
This crate is intended as the main interchange format with outside code. A typical integration with React Compiler
|
||||
will look as follows:
|
||||
|
||||
1. Host Compiler parses into the host AST format.
|
||||
2. Host Compiler converts into `react_estree`.
|
||||
3. Host Compiler invokes React Compiler to compile the input, which (conceptually)
|
||||
returns the resulting code in `react_estree` format.
|
||||
4. Host Compiler convert back from `react_estree` to its host AST format.
|
||||
|
||||
Because React Compiler is intended to support JavaScript-based toolchains, `react_estree` is designed to support
|
||||
accurate serialization to/from estree-compatible JSON. We may also support the Babel AST format
|
||||
(a variant of ESTree) as well, depending on demand.
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use react_estree_codegen::estree;
|
||||
|
||||
// Example custom build script.
|
||||
fn main() {
|
||||
// Re-run if the codegen files change
|
||||
println!("cargo:rerun-if-changed=../react_estree_codegen/src/codegen.rs");
|
||||
println!("cargo:rerun-if-changed=../react_estree_codegen/src/lib.rs");
|
||||
println!("cargo:rerun-if-changed=../react_estree_codegen/src/ecmascript.json");
|
||||
println!("cargo:rerun-if-changed=../react_estree_codegen");
|
||||
|
||||
let src = estree();
|
||||
let copyright = "
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
"
|
||||
.to_string();
|
||||
let trimmed_copyright = copyright.trim();
|
||||
let contents = format!("{trimmed_copyright}\n{src}");
|
||||
std::fs::write("src/generated.rs", contents).unwrap();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Binding {
|
||||
Global,
|
||||
Module(BindingId),
|
||||
Local(BindingId),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct BindingId(u32);
|
||||
|
||||
impl BindingId {
|
||||
pub fn new(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BindingId> for u32 {
|
||||
fn from(value: BindingId) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
@@ -1,528 +0,0 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 7,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 7,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
}
|
||||
},
|
||||
"name": "Component",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
9,
|
||||
18
|
||||
]
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
19,
|
||||
24
|
||||
]
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 7,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "VariableDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"kind": "let",
|
||||
"declarations": [
|
||||
{
|
||||
"type": "VariableDeclarator",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 6
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 11
|
||||
}
|
||||
},
|
||||
"init": {
|
||||
"type": "Literal",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 11
|
||||
}
|
||||
},
|
||||
"value": 0,
|
||||
"range": [
|
||||
38,
|
||||
39
|
||||
],
|
||||
"raw": "0"
|
||||
},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 6
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 7
|
||||
}
|
||||
},
|
||||
"name": "x",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
34,
|
||||
35
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
34,
|
||||
39
|
||||
]
|
||||
}
|
||||
],
|
||||
"range": [
|
||||
30,
|
||||
40
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "ForStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 5,
|
||||
"column": 3
|
||||
}
|
||||
},
|
||||
"init": {
|
||||
"type": "VariableDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 16
|
||||
}
|
||||
},
|
||||
"kind": "let",
|
||||
"declarations": [
|
||||
{
|
||||
"type": "VariableDeclarator",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 11
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 16
|
||||
}
|
||||
},
|
||||
"init": {
|
||||
"type": "Literal",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 16
|
||||
}
|
||||
},
|
||||
"value": 0,
|
||||
"range": [
|
||||
56,
|
||||
57
|
||||
],
|
||||
"raw": "0"
|
||||
},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 11
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"name": "i",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
52,
|
||||
53
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
52,
|
||||
57
|
||||
]
|
||||
}
|
||||
],
|
||||
"range": [
|
||||
48,
|
||||
57
|
||||
]
|
||||
},
|
||||
"test": {
|
||||
"type": "BinaryExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"left": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 19
|
||||
}
|
||||
},
|
||||
"name": "i",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
59,
|
||||
60
|
||||
]
|
||||
},
|
||||
"right": {
|
||||
"type": "Literal",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 22
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"value": 10,
|
||||
"range": [
|
||||
63,
|
||||
65
|
||||
],
|
||||
"raw": "10"
|
||||
},
|
||||
"operator": "<",
|
||||
"range": [
|
||||
59,
|
||||
65
|
||||
]
|
||||
},
|
||||
"update": {
|
||||
"type": "UpdateExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 29
|
||||
}
|
||||
},
|
||||
"operator": "++",
|
||||
"argument": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 27
|
||||
}
|
||||
},
|
||||
"name": "i",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
67,
|
||||
68
|
||||
]
|
||||
},
|
||||
"prefix": false,
|
||||
"range": [
|
||||
67,
|
||||
70
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 31
|
||||
},
|
||||
"end": {
|
||||
"line": 5,
|
||||
"column": 3
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "ExpressionStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 4,
|
||||
"column": 4
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 11
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"type": "AssignmentExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 4,
|
||||
"column": 4
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 10
|
||||
}
|
||||
},
|
||||
"operator": "+=",
|
||||
"left": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 4,
|
||||
"column": 4
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 5
|
||||
}
|
||||
},
|
||||
"name": "x",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
78,
|
||||
79
|
||||
]
|
||||
},
|
||||
"right": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 4,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 10
|
||||
}
|
||||
},
|
||||
"name": "i",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
83,
|
||||
84
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
78,
|
||||
84
|
||||
]
|
||||
},
|
||||
"directive": null,
|
||||
"range": [
|
||||
78,
|
||||
85
|
||||
]
|
||||
}
|
||||
],
|
||||
"range": [
|
||||
72,
|
||||
89
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
43,
|
||||
89
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 6,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 6,
|
||||
"column": 11
|
||||
}
|
||||
},
|
||||
"argument": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 6,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 6,
|
||||
"column": 10
|
||||
}
|
||||
},
|
||||
"name": "x",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
99,
|
||||
100
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
92,
|
||||
101
|
||||
]
|
||||
}
|
||||
],
|
||||
"range": [
|
||||
26,
|
||||
103
|
||||
]
|
||||
},
|
||||
"typeParameters": null,
|
||||
"returnType": null,
|
||||
"predicate": null,
|
||||
"generator": false,
|
||||
"async": false,
|
||||
"range": [
|
||||
0,
|
||||
103
|
||||
]
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"interpreter": null,
|
||||
"range": [
|
||||
0,
|
||||
103
|
||||
],
|
||||
"sourceType": "script"
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "ImportDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"specifiers": [
|
||||
{
|
||||
"type": "ImportDefaultSpecifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"local": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"name": "React",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": {
|
||||
"type": "Literal",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 25
|
||||
}
|
||||
},
|
||||
"value": "react",
|
||||
"range": [
|
||||
18,
|
||||
25
|
||||
],
|
||||
"raw": "'react'"
|
||||
},
|
||||
"attributes": [],
|
||||
"importKind": "value",
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
]
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"interpreter": null,
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
],
|
||||
"sourceType": "module"
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
],
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
9,
|
||||
18
|
||||
],
|
||||
"name": "Component",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
19,
|
||||
24
|
||||
],
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
26,
|
||||
51
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 21
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
30,
|
||||
49
|
||||
],
|
||||
"argument": {
|
||||
"type": "MemberExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
48
|
||||
],
|
||||
"object": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 14
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
42
|
||||
],
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
},
|
||||
"property": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
43,
|
||||
48
|
||||
],
|
||||
"name": "value",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
},
|
||||
"computed": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"async": false,
|
||||
"generator": false,
|
||||
"predicate": null,
|
||||
"expression": false,
|
||||
"returnType": null,
|
||||
"typeParameters": null
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"errors": []
|
||||
}
|
||||
@@ -1,351 +0,0 @@
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"name": "foo",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
10,
|
||||
13
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"argument": {
|
||||
"type": "JSXElement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"openingElement": {
|
||||
"type": "JSXOpeningElement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 13
|
||||
}
|
||||
},
|
||||
"name": "Foo",
|
||||
"range": [
|
||||
28,
|
||||
31
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 14
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"name": "Bar",
|
||||
"range": [
|
||||
32,
|
||||
35
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
28,
|
||||
35
|
||||
]
|
||||
},
|
||||
"attributes": [
|
||||
{
|
||||
"type": "JSXAttribute",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 19
|
||||
}
|
||||
},
|
||||
"name": "a",
|
||||
"range": [
|
||||
36,
|
||||
37
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "JSXExpressionContainer",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 20
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 21
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 23
|
||||
}
|
||||
},
|
||||
"value": 10,
|
||||
"range": [
|
||||
39,
|
||||
41
|
||||
],
|
||||
"raw": "10"
|
||||
},
|
||||
"range": [
|
||||
38,
|
||||
42
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
36,
|
||||
42
|
||||
]
|
||||
}
|
||||
],
|
||||
"selfClosing": false,
|
||||
"range": [
|
||||
27,
|
||||
44
|
||||
]
|
||||
},
|
||||
"children": [],
|
||||
"closingElement": {
|
||||
"type": "JSXClosingElement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 31
|
||||
}
|
||||
},
|
||||
"name": "Foo",
|
||||
"range": [
|
||||
46,
|
||||
49
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 32
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"name": "Bar",
|
||||
"range": [
|
||||
50,
|
||||
53
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
46,
|
||||
53
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
44,
|
||||
54
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
27,
|
||||
54
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
20,
|
||||
54
|
||||
]
|
||||
}
|
||||
],
|
||||
"range": [
|
||||
16,
|
||||
56
|
||||
]
|
||||
},
|
||||
"typeParameters": null,
|
||||
"returnType": null,
|
||||
"predicate": null,
|
||||
"generator": false,
|
||||
"async": false,
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
]
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"interpreter": null,
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
],
|
||||
"sourceType": "script"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
// Manual extensions to generated types
|
||||
use crate::{
|
||||
ArrowFunctionExpression, Class, ClassDeclaration, ClassExpression, Function,
|
||||
FunctionDeclaration, FunctionExpression, ImportDeclarationSpecifier, JSXElementName,
|
||||
JSXMemberExpression, JSXMemberExpressionOrIdentifier, Pattern, SourceRange, SourceType,
|
||||
};
|
||||
|
||||
/// Sentinel trait to distinguish AST *node* types
|
||||
pub trait ESTreeNode {}
|
||||
|
||||
impl Default for SourceType {
|
||||
fn default() -> Self {
|
||||
Self::Module
|
||||
}
|
||||
}
|
||||
|
||||
impl Pattern {
|
||||
pub fn range(&self) -> Option<SourceRange> {
|
||||
match self {
|
||||
Self::ArrayPattern(pattern) => pattern.range,
|
||||
Self::AssignmentPattern(pattern) => pattern.range,
|
||||
Self::Identifier(pattern) => pattern.range,
|
||||
Self::ObjectPattern(pattern) => pattern.range,
|
||||
Self::RestElement(pattern) => pattern.range,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportDeclarationSpecifier {
|
||||
pub fn range(&self) -> Option<SourceRange> {
|
||||
match self {
|
||||
Self::ImportDefaultSpecifier(specifier) => specifier.range,
|
||||
Self::ImportNamespaceSpecifier(specifier) => specifier.range,
|
||||
Self::ImportSpecifier(specifier) => specifier.range,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl JSXElementName {
|
||||
pub fn root_name(&self) -> &str {
|
||||
match self {
|
||||
Self::JSXIdentifier(name) => &name.name,
|
||||
Self::JSXMemberExpression(name) => name.root_name(),
|
||||
Self::JSXNamespacedName(name) => &name.namespace.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl JSXMemberExpression {
|
||||
pub fn root_name(&self) -> &str {
|
||||
match &self.object {
|
||||
JSXMemberExpressionOrIdentifier::JSXMemberExpression(object) => object.root_name(),
|
||||
JSXMemberExpressionOrIdentifier::JSXIdentifier(object) => &object.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoFunction: ESTreeNode {
|
||||
fn function(&self) -> &Function;
|
||||
|
||||
fn into_function(self) -> Function;
|
||||
}
|
||||
|
||||
impl IntoFunction for FunctionDeclaration {
|
||||
fn function(&self) -> &Function {
|
||||
&self.function
|
||||
}
|
||||
|
||||
fn into_function(self) -> Function {
|
||||
self.function
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoFunction for FunctionExpression {
|
||||
fn function(&self) -> &Function {
|
||||
&self.function
|
||||
}
|
||||
|
||||
fn into_function(self) -> Function {
|
||||
self.function
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoFunction for ArrowFunctionExpression {
|
||||
fn function(&self) -> &Function {
|
||||
&self.function
|
||||
}
|
||||
|
||||
fn into_function(self) -> Function {
|
||||
self.function
|
||||
}
|
||||
}
|
||||
|
||||
impl ESTreeNode for Function {}
|
||||
|
||||
impl IntoFunction for Function {
|
||||
fn function(&self) -> &Function {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_function(self) -> Function {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoClass: ESTreeNode {
|
||||
fn class(&self) -> &Class;
|
||||
|
||||
fn into_class(self) -> Class;
|
||||
}
|
||||
|
||||
impl IntoClass for ClassDeclaration {
|
||||
fn class(&self) -> &Class {
|
||||
&self.class
|
||||
}
|
||||
|
||||
fn into_class(self) -> Class {
|
||||
self.class
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoClass for ClassExpression {
|
||||
fn class(&self) -> &Class {
|
||||
&self.class
|
||||
}
|
||||
|
||||
fn into_class(self) -> Class {
|
||||
self.class
|
||||
}
|
||||
}
|
||||
|
||||
impl ESTreeNode for Class {}
|
||||
|
||||
impl IntoClass for Class {
|
||||
fn class(&self) -> &Class {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_class(self) -> Class {
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use serde::de::Visitor;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum JsValue {
|
||||
Boolean(bool),
|
||||
Null,
|
||||
Number(Number),
|
||||
String(String),
|
||||
Undefined,
|
||||
}
|
||||
|
||||
impl JsValue {
|
||||
pub fn is_truthy(&self) -> bool {
|
||||
match &self {
|
||||
JsValue::Boolean(value) => *value,
|
||||
JsValue::Number(value) => value.is_truthy(),
|
||||
JsValue::String(value) => !value.is_empty(),
|
||||
JsValue::Null => false,
|
||||
JsValue::Undefined => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Partial implementation of loose equality for javascript, returns Some for supported
|
||||
// cases w the equality result, and None for unsupported cases
|
||||
pub fn loosely_equals(&self, other: &Self) -> Option<bool> {
|
||||
// https://tc39.es/ecma262/multipage/abstract-operations.html#sec-islooselyequal
|
||||
match (&self, &other) {
|
||||
// 1. If Type(x) is Type(y), then
|
||||
// a. Return IsStrictlyEqual(x, y).
|
||||
(JsValue::Number(left), JsValue::Number(right)) => Some(left.equals(*right)),
|
||||
(JsValue::Null, JsValue::Null) => Some(true),
|
||||
(JsValue::Undefined, JsValue::Undefined) => Some(true),
|
||||
(JsValue::Boolean(left), JsValue::Boolean(right)) => Some(left == right),
|
||||
(JsValue::String(left), JsValue::String(right)) => Some(left == right),
|
||||
|
||||
// 2. If x is null and y is undefined, return true.
|
||||
(JsValue::Null, JsValue::Undefined) => Some(true),
|
||||
|
||||
// 3. If x is undefined and y is null, return true.
|
||||
(JsValue::Undefined, JsValue::Null) => Some(true),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_loosely_equals(&self, other: &Self) -> Option<bool> {
|
||||
self.loosely_equals(other).map(|value| !value)
|
||||
}
|
||||
|
||||
// Complete implementation of strict equality for javascript
|
||||
pub fn strictly_equals(&self, other: &Self) -> bool {
|
||||
// https://tc39.es/ecma262/multipage/abstract-operations.html#sec-isstrictlyequal
|
||||
match (&self, &other) {
|
||||
(JsValue::Number(left), JsValue::Number(right)) => left.equals(*right),
|
||||
(JsValue::Null, JsValue::Null) => true,
|
||||
(JsValue::Undefined, JsValue::Undefined) => true,
|
||||
(JsValue::Boolean(left), JsValue::Boolean(right)) => left == right,
|
||||
(JsValue::String(left), JsValue::String(right)) => left == right,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_strictly_equals(&self, other: &Self) -> bool {
|
||||
!self.strictly_equals(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for JsValue {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
match self {
|
||||
Self::Boolean(b) => serializer.serialize_bool(*b),
|
||||
Self::Null => serializer.serialize_none(),
|
||||
Self::Number(n) => serializer.serialize_f64(n.into()),
|
||||
Self::String(s) => serializer.serialize_str(s),
|
||||
Self::Undefined => serializer.serialize_unit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for JsValue {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<JsValue, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct ValueVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ValueVisitor {
|
||||
type Value = JsValue;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("valid primitive JSON value (null, boolean, number, or string")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bool<E>(self, value: bool) -> Result<JsValue, E> {
|
||||
Ok(JsValue::Boolean(value))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_i64<E>(self, value: i64) -> Result<JsValue, E> {
|
||||
if (MIN_SAFE_INT..=MAX_SAFE_INT).contains(&value) {
|
||||
Ok(JsValue::Number((value as f64).into()))
|
||||
} else {
|
||||
panic!("Invalid number")
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_u64<E>(self, value: u64) -> Result<JsValue, E> {
|
||||
if value as i64 <= MAX_SAFE_INT {
|
||||
Ok(JsValue::Number((value as f64).into()))
|
||||
} else {
|
||||
panic!("Invalid number")
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_f64<E>(self, value: f64) -> Result<JsValue, E> {
|
||||
Ok(JsValue::Number(value.into()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_str<E>(self, value: &str) -> Result<JsValue, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
self.visit_string(String::from(value))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_string<E>(self, value: String) -> Result<JsValue, E> {
|
||||
Ok(JsValue::String(value))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_none<E>(self) -> Result<JsValue, E> {
|
||||
Ok(JsValue::Null)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_some<D>(self, deserializer: D) -> Result<JsValue, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
Deserialize::deserialize(deserializer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(self) -> Result<JsValue, E> {
|
||||
Ok(JsValue::Undefined)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(ValueVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a JavaScript Number as its binary representation so that
|
||||
/// -1 == -1, NaN == Nan etc.
|
||||
/// Note: NaN is *always* represented as the f64::NAN constant to allow
|
||||
/// comparison of NaNs.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Number(u64);
|
||||
|
||||
pub const MAX_SAFE_INT: i64 = 9007199254740991;
|
||||
pub const MIN_SAFE_INT: i64 = -9007199254740991;
|
||||
|
||||
impl From<f64> for Number {
|
||||
fn from(value: f64) -> Self {
|
||||
if value.is_nan() {
|
||||
Self(f64::NAN.to_bits())
|
||||
} else {
|
||||
Self(value.to_bits())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Number {
|
||||
fn from(value: u32) -> Self {
|
||||
f64::from(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Number> for f64 {
|
||||
fn from(number: Number) -> Self {
|
||||
let value = f64::from_bits(number.0);
|
||||
assert!(!f64::is_nan(value) || number.0 == f64::NAN.to_bits());
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Number> for f64 {
|
||||
fn from(number: &Number) -> Self {
|
||||
let value = f64::from_bits(number.0);
|
||||
assert!(!f64::is_nan(value) || number.0 == f64::NAN.to_bits());
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
impl Number {
|
||||
pub fn equals(self, other: Self) -> bool {
|
||||
f64::from(self) == f64::from(other)
|
||||
}
|
||||
|
||||
pub fn not_equals(self, other: Self) -> bool {
|
||||
!self.equals(other)
|
||||
}
|
||||
|
||||
pub fn is_truthy(self) -> bool {
|
||||
let value = f64::from(self);
|
||||
!(self.0 == f64::NAN.to_bits() || value == 0.0 || value == -0.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add for Number {
|
||||
type Output = Number;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
let result = f64::from(self) + f64::from(rhs);
|
||||
Self::from(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for Number {
|
||||
type Output = Number;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
let result = f64::from(self) - f64::from(rhs);
|
||||
Self::from(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul for Number {
|
||||
type Output = Number;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
let result = f64::from(self) * f64::from(rhs);
|
||||
Self::from(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Div for Number {
|
||||
type Output = Number;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
let result = f64::from(self) / f64::from(rhs);
|
||||
Self::from(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Number {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_f64(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Number {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct ValueVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ValueVisitor {
|
||||
type Value = Number;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("value JavaScript number value")
|
||||
}
|
||||
|
||||
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(ValueVisitor)
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
mod binding;
|
||||
mod generated;
|
||||
mod generated_extensions;
|
||||
mod js_value;
|
||||
mod range;
|
||||
mod visit;
|
||||
|
||||
pub use binding::{Binding, BindingId};
|
||||
pub use generated::*;
|
||||
pub use generated_extensions::*;
|
||||
pub use js_value::{JsValue, Number};
|
||||
pub use range::SourceRange;
|
||||
pub use visit::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::{assert_snapshot, glob};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fixtures() {
|
||||
glob!("fixtures/**.json", |path| {
|
||||
println!("{:?}", path);
|
||||
let input = std::fs::read_to_string(path).unwrap();
|
||||
let ast: Program = serde_json::from_str(&input).unwrap();
|
||||
let serialized = serde_json::to_string_pretty(&ast).unwrap();
|
||||
assert_snapshot!(format!("Input:\n{input}\n\nOutput:\n{serialized}"));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use serde::ser::SerializeTuple;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
|
||||
pub struct SourceRange {
|
||||
pub start: u32,
|
||||
pub end: NonZeroU32,
|
||||
}
|
||||
|
||||
// ESTree and Babel store the `range` as `[start, end]`, so we customize
|
||||
// the serialization to use a tuple representation.
|
||||
impl Serialize for SourceRange {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut tuple = serializer.serialize_tuple(2)?;
|
||||
tuple.serialize_element(&self.start)?;
|
||||
tuple.serialize_element(&self.end)?;
|
||||
tuple.end()
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,213 +0,0 @@
|
||||
---
|
||||
source: crates/react_estree/src/lib.rs
|
||||
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{serialized}\")"
|
||||
input_file: crates/react_estree/src/fixtures/import.json
|
||||
---
|
||||
Input:
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "ImportDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"specifiers": [
|
||||
{
|
||||
"type": "ImportDefaultSpecifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"local": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"name": "React",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": {
|
||||
"type": "Literal",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 25
|
||||
}
|
||||
},
|
||||
"value": "react",
|
||||
"range": [
|
||||
18,
|
||||
25
|
||||
],
|
||||
"raw": "'react'"
|
||||
},
|
||||
"attributes": [],
|
||||
"importKind": "value",
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
]
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"interpreter": null,
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
],
|
||||
"sourceType": "module"
|
||||
}
|
||||
|
||||
Output:
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ImportDeclaration",
|
||||
"specifiers": [
|
||||
{
|
||||
"type": "ImportDefaultSpecifier",
|
||||
"local": {
|
||||
"type": "Identifier",
|
||||
"name": "React",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": {
|
||||
"type": "Literal",
|
||||
"value": "react",
|
||||
"raw": "'react'",
|
||||
"regex": null,
|
||||
"bigint": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 25
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
18,
|
||||
25
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
]
|
||||
}
|
||||
],
|
||||
"sourceType": "module",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
]
|
||||
}
|
||||
@@ -1,379 +0,0 @@
|
||||
---
|
||||
source: crates/react_estree/src/lib.rs
|
||||
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{serialized}\")"
|
||||
input_file: crates/react_estree/src/fixtures/simple.json
|
||||
---
|
||||
Input:
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
],
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
9,
|
||||
18
|
||||
],
|
||||
"name": "Component",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
19,
|
||||
24
|
||||
],
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
26,
|
||||
51
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 21
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
30,
|
||||
49
|
||||
],
|
||||
"argument": {
|
||||
"type": "MemberExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
48
|
||||
],
|
||||
"object": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 14
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
42
|
||||
],
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
},
|
||||
"property": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
43,
|
||||
48
|
||||
],
|
||||
"name": "value",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
},
|
||||
"computed": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"async": false,
|
||||
"generator": false,
|
||||
"predicate": null,
|
||||
"expression": false,
|
||||
"returnType": null,
|
||||
"typeParameters": null
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"errors": []
|
||||
}
|
||||
|
||||
Output:
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"name": "Component",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
9,
|
||||
18
|
||||
]
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "Identifier",
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
19,
|
||||
24
|
||||
]
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"argument": {
|
||||
"type": "MemberExpression",
|
||||
"object": {
|
||||
"type": "Identifier",
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 14
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
42
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "Identifier",
|
||||
"name": "value",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
43,
|
||||
48
|
||||
]
|
||||
},
|
||||
"computed": false,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
48
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 21
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
30,
|
||||
49
|
||||
]
|
||||
}
|
||||
],
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
26,
|
||||
51
|
||||
]
|
||||
},
|
||||
"generator": false,
|
||||
"async": false,
|
||||
"loc": null,
|
||||
"range": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
]
|
||||
}
|
||||
],
|
||||
"sourceType": "module",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
]
|
||||
}
|
||||
@@ -1,708 +0,0 @@
|
||||
---
|
||||
source: crates/react_estree/src/lib.rs
|
||||
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{serialized}\")"
|
||||
input_file: crates/react_estree/src/fixtures/test.json
|
||||
---
|
||||
Input:
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"name": "foo",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
10,
|
||||
13
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"argument": {
|
||||
"type": "JSXElement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"openingElement": {
|
||||
"type": "JSXOpeningElement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 13
|
||||
}
|
||||
},
|
||||
"name": "Foo",
|
||||
"range": [
|
||||
28,
|
||||
31
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 14
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"name": "Bar",
|
||||
"range": [
|
||||
32,
|
||||
35
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
28,
|
||||
35
|
||||
]
|
||||
},
|
||||
"attributes": [
|
||||
{
|
||||
"type": "JSXAttribute",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 19
|
||||
}
|
||||
},
|
||||
"name": "a",
|
||||
"range": [
|
||||
36,
|
||||
37
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "JSXExpressionContainer",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 20
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 21
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 23
|
||||
}
|
||||
},
|
||||
"value": 10,
|
||||
"range": [
|
||||
39,
|
||||
41
|
||||
],
|
||||
"raw": "10"
|
||||
},
|
||||
"range": [
|
||||
38,
|
||||
42
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
36,
|
||||
42
|
||||
]
|
||||
}
|
||||
],
|
||||
"selfClosing": false,
|
||||
"range": [
|
||||
27,
|
||||
44
|
||||
]
|
||||
},
|
||||
"children": [],
|
||||
"closingElement": {
|
||||
"type": "JSXClosingElement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 31
|
||||
}
|
||||
},
|
||||
"name": "Foo",
|
||||
"range": [
|
||||
46,
|
||||
49
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 32
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"name": "Bar",
|
||||
"range": [
|
||||
50,
|
||||
53
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
46,
|
||||
53
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
44,
|
||||
54
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
27,
|
||||
54
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
20,
|
||||
54
|
||||
]
|
||||
}
|
||||
],
|
||||
"range": [
|
||||
16,
|
||||
56
|
||||
]
|
||||
},
|
||||
"typeParameters": null,
|
||||
"returnType": null,
|
||||
"predicate": null,
|
||||
"generator": false,
|
||||
"async": false,
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
]
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"interpreter": null,
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
],
|
||||
"sourceType": "script"
|
||||
}
|
||||
|
||||
Output:
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"name": "foo",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
10,
|
||||
13
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"argument": {
|
||||
"type": "JSXElement",
|
||||
"openingElement": {
|
||||
"type": "JSXOpeningElement",
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "Foo",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 13
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
28,
|
||||
31
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "Bar",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 14
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
32,
|
||||
35
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
28,
|
||||
35
|
||||
]
|
||||
},
|
||||
"attributes": [
|
||||
{
|
||||
"type": "JSXAttribute",
|
||||
"name": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "a",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 19
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
36,
|
||||
37
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "JSXExpressionContainer",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": 10.0,
|
||||
"raw": "10",
|
||||
"regex": null,
|
||||
"bigint": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 21
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 23
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
39,
|
||||
41
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 20
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
38,
|
||||
42
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
36,
|
||||
42
|
||||
]
|
||||
}
|
||||
],
|
||||
"selfClosing": false,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
27,
|
||||
44
|
||||
]
|
||||
},
|
||||
"children": [],
|
||||
"closingElement": {
|
||||
"type": "JSXClosingElement",
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "Foo",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 31
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
46,
|
||||
49
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "Bar",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 32
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
50,
|
||||
53
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
46,
|
||||
53
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
44,
|
||||
54
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
27,
|
||||
54
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
20,
|
||||
54
|
||||
]
|
||||
}
|
||||
],
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
16,
|
||||
56
|
||||
]
|
||||
},
|
||||
"generator": false,
|
||||
"async": false,
|
||||
"loc": null,
|
||||
"range": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
]
|
||||
}
|
||||
],
|
||||
"sourceType": "script",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,213 +0,0 @@
|
||||
---
|
||||
source: crates/react_estree/src/lib.rs
|
||||
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{serialized}\")"
|
||||
input_file: crates/react_estree/src/fixtures/import.json
|
||||
---
|
||||
Input:
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "ImportDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"specifiers": [
|
||||
{
|
||||
"type": "ImportDefaultSpecifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"local": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"name": "React",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": {
|
||||
"type": "Literal",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 25
|
||||
}
|
||||
},
|
||||
"value": "react",
|
||||
"range": [
|
||||
18,
|
||||
25
|
||||
],
|
||||
"raw": "'react'"
|
||||
},
|
||||
"attributes": [],
|
||||
"importKind": "value",
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
]
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"interpreter": null,
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
],
|
||||
"sourceType": "module"
|
||||
}
|
||||
|
||||
Output:
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "ImportDeclaration",
|
||||
"specifiers": [
|
||||
{
|
||||
"type": "ImportDefaultSpecifier",
|
||||
"local": {
|
||||
"type": "Identifier",
|
||||
"name": "React",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 7
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
7,
|
||||
12
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": {
|
||||
"type": "Literal",
|
||||
"value": "react",
|
||||
"raw": "'react'",
|
||||
"regex": null,
|
||||
"bigint": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 25
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
18,
|
||||
25
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
]
|
||||
}
|
||||
],
|
||||
"sourceType": "module",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
26
|
||||
]
|
||||
}
|
||||
@@ -1,379 +0,0 @@
|
||||
---
|
||||
source: crates/react_estree/src/lib.rs
|
||||
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{serialized}\")"
|
||||
input_file: crates/react_estree/src/fixtures/simple.json
|
||||
---
|
||||
Input:
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
],
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
9,
|
||||
18
|
||||
],
|
||||
"name": "Component",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
19,
|
||||
24
|
||||
],
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
26,
|
||||
51
|
||||
],
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 21
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
30,
|
||||
49
|
||||
],
|
||||
"argument": {
|
||||
"type": "MemberExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
48
|
||||
],
|
||||
"object": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 14
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
42
|
||||
],
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
},
|
||||
"property": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
43,
|
||||
48
|
||||
],
|
||||
"name": "value",
|
||||
"typeAnnotation": null,
|
||||
"optional": false
|
||||
},
|
||||
"computed": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"async": false,
|
||||
"generator": false,
|
||||
"predicate": null,
|
||||
"expression": false,
|
||||
"returnType": null,
|
||||
"typeParameters": null
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"errors": []
|
||||
}
|
||||
|
||||
Output:
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"name": "Component",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 18
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
9,
|
||||
18
|
||||
]
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"type": "Identifier",
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
19,
|
||||
24
|
||||
]
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"argument": {
|
||||
"type": "MemberExpression",
|
||||
"object": {
|
||||
"type": "Identifier",
|
||||
"name": "props",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 14
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
42
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "Identifier",
|
||||
"name": "value",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
43,
|
||||
48
|
||||
]
|
||||
},
|
||||
"computed": false,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 20
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
37,
|
||||
48
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 21
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
30,
|
||||
49
|
||||
]
|
||||
}
|
||||
],
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
26,
|
||||
51
|
||||
]
|
||||
},
|
||||
"generator": false,
|
||||
"async": false,
|
||||
"loc": null,
|
||||
"range": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
]
|
||||
}
|
||||
],
|
||||
"sourceType": "module",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
51
|
||||
]
|
||||
}
|
||||
@@ -1,708 +0,0 @@
|
||||
---
|
||||
source: crates/react_estree/src/lib.rs
|
||||
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{serialized}\")"
|
||||
input_file: crates/react_estree/src/fixtures/test.json
|
||||
---
|
||||
Input:
|
||||
{
|
||||
"type": "Program",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"name": "foo",
|
||||
"typeAnnotation": null,
|
||||
"optional": false,
|
||||
"range": [
|
||||
10,
|
||||
13
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"argument": {
|
||||
"type": "JSXElement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"openingElement": {
|
||||
"type": "JSXOpeningElement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 13
|
||||
}
|
||||
},
|
||||
"name": "Foo",
|
||||
"range": [
|
||||
28,
|
||||
31
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 14
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"name": "Bar",
|
||||
"range": [
|
||||
32,
|
||||
35
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
28,
|
||||
35
|
||||
]
|
||||
},
|
||||
"attributes": [
|
||||
{
|
||||
"type": "JSXAttribute",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 19
|
||||
}
|
||||
},
|
||||
"name": "a",
|
||||
"range": [
|
||||
36,
|
||||
37
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "JSXExpressionContainer",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 20
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 21
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 23
|
||||
}
|
||||
},
|
||||
"value": 10,
|
||||
"range": [
|
||||
39,
|
||||
41
|
||||
],
|
||||
"raw": "10"
|
||||
},
|
||||
"range": [
|
||||
38,
|
||||
42
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
36,
|
||||
42
|
||||
]
|
||||
}
|
||||
],
|
||||
"selfClosing": false,
|
||||
"range": [
|
||||
27,
|
||||
44
|
||||
]
|
||||
},
|
||||
"children": [],
|
||||
"closingElement": {
|
||||
"type": "JSXClosingElement",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 31
|
||||
}
|
||||
},
|
||||
"name": "Foo",
|
||||
"range": [
|
||||
46,
|
||||
49
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 32
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"name": "Bar",
|
||||
"range": [
|
||||
50,
|
||||
53
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
46,
|
||||
53
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
44,
|
||||
54
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
27,
|
||||
54
|
||||
]
|
||||
},
|
||||
"range": [
|
||||
20,
|
||||
54
|
||||
]
|
||||
}
|
||||
],
|
||||
"range": [
|
||||
16,
|
||||
56
|
||||
]
|
||||
},
|
||||
"typeParameters": null,
|
||||
"returnType": null,
|
||||
"predicate": null,
|
||||
"generator": false,
|
||||
"async": false,
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
]
|
||||
}
|
||||
],
|
||||
"comments": [],
|
||||
"interpreter": null,
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
],
|
||||
"sourceType": "script"
|
||||
}
|
||||
|
||||
Output:
|
||||
{
|
||||
"type": "Program",
|
||||
"body": [
|
||||
{
|
||||
"type": "FunctionDeclaration",
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"name": "foo",
|
||||
"typeAnnotation": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 12
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
10,
|
||||
13
|
||||
]
|
||||
},
|
||||
"params": [],
|
||||
"body": {
|
||||
"type": "BlockStatement",
|
||||
"body": [
|
||||
{
|
||||
"type": "ReturnStatement",
|
||||
"argument": {
|
||||
"type": "JSXElement",
|
||||
"openingElement": {
|
||||
"type": "JSXOpeningElement",
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "Foo",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 13
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
28,
|
||||
31
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "Bar",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 14
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
32,
|
||||
35
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 10
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 17
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
28,
|
||||
35
|
||||
]
|
||||
},
|
||||
"attributes": [
|
||||
{
|
||||
"type": "JSXAttribute",
|
||||
"name": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "a",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 19
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
36,
|
||||
37
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"type": "JSXExpressionContainer",
|
||||
"expression": {
|
||||
"type": "Literal",
|
||||
"value": 10.0,
|
||||
"raw": "10",
|
||||
"regex": null,
|
||||
"bigint": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 21
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 23
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
39,
|
||||
41
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 20
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
38,
|
||||
42
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 24
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
36,
|
||||
42
|
||||
]
|
||||
}
|
||||
],
|
||||
"selfClosing": false,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
27,
|
||||
44
|
||||
]
|
||||
},
|
||||
"children": [],
|
||||
"closingElement": {
|
||||
"type": "JSXClosingElement",
|
||||
"name": {
|
||||
"type": "JSXMemberExpression",
|
||||
"object": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "Foo",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 31
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
46,
|
||||
49
|
||||
]
|
||||
},
|
||||
"property": {
|
||||
"type": "JSXIdentifier",
|
||||
"name": "Bar",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 32
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
50,
|
||||
53
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 28
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 35
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
46,
|
||||
53
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 26
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
44,
|
||||
54
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 9
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
27,
|
||||
54
|
||||
]
|
||||
},
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 3,
|
||||
"column": 2
|
||||
},
|
||||
"end": {
|
||||
"line": 3,
|
||||
"column": 36
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
20,
|
||||
54
|
||||
]
|
||||
}
|
||||
],
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
16,
|
||||
56
|
||||
]
|
||||
},
|
||||
"generator": false,
|
||||
"async": false,
|
||||
"loc": null,
|
||||
"range": null,
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
]
|
||||
}
|
||||
],
|
||||
"sourceType": "script",
|
||||
"loc": {
|
||||
"source": null,
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 0
|
||||
},
|
||||
"end": {
|
||||
"line": 4,
|
||||
"column": 1
|
||||
}
|
||||
},
|
||||
"range": [
|
||||
1,
|
||||
56
|
||||
]
|
||||
}
|
||||
@@ -1,537 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use crate::{
|
||||
AssignmentPropertyOrRestElement, AssignmentTarget, Class, ClassItem, ClassPrivateProperty,
|
||||
ClassProperty, Declaration, DeclarationOrExpression, ExportAllDeclaration,
|
||||
ExportDefaultDeclaration, ExportNamedDeclaration, Expression, ExpressionOrPrivateIdentifier,
|
||||
ExpressionOrSpread, ExpressionOrSuper, ForInInit, ForInit, Function, FunctionBody,
|
||||
FunctionDeclaration, Identifier, ImportDeclaration, ImportDeclarationSpecifier,
|
||||
ImportOrExportDeclaration, Literal, MethodDefinition, ModuleItem, Pattern, PrivateIdentifier,
|
||||
PrivateName, Program, Statement, StaticBlock, Super, SwitchCase, VariableDeclarator, _Literal,
|
||||
};
|
||||
|
||||
/// Trait for visiting an estree
|
||||
#[allow(non_camel_case_types)]
|
||||
#[deprecated]
|
||||
pub trait Visitor_DEPRECATED<'ast> {
|
||||
fn visit_lvalue<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnOnce(&mut Self),
|
||||
{
|
||||
f(self);
|
||||
}
|
||||
|
||||
fn visit_rvalue<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnOnce(&mut Self),
|
||||
{
|
||||
f(self);
|
||||
}
|
||||
|
||||
fn visit_program(&mut self, program: &'ast Program) {
|
||||
self.default_visit_program(program)
|
||||
}
|
||||
|
||||
fn default_visit_program(&mut self, program: &'ast Program) {
|
||||
for item in &program.body {
|
||||
self.visit_module_item(item);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_function(&mut self, function: &'ast Function) {
|
||||
self.default_visit_function(function);
|
||||
}
|
||||
|
||||
fn default_visit_function(&mut self, function: &'ast Function) {
|
||||
self.visit_lvalue(|visitor| {
|
||||
for param in &function.params {
|
||||
visitor.visit_pattern(param);
|
||||
}
|
||||
});
|
||||
match &function.body {
|
||||
Some(FunctionBody::BlockStatement(body)) => {
|
||||
for stmt in &body.body {
|
||||
self.visit_statement(stmt)
|
||||
}
|
||||
}
|
||||
Some(FunctionBody::Expression(body)) => self.visit_expression(body),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_module_item(&mut self, item: &'ast ModuleItem) {
|
||||
match item {
|
||||
ModuleItem::Statement(item) => self.visit_statement(item),
|
||||
ModuleItem::ImportOrExportDeclaration(item) => {
|
||||
self.visit_import_or_export_declaration(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_import_or_export_declaration(&mut self, declaration: &'ast ImportOrExportDeclaration) {
|
||||
match declaration {
|
||||
ImportOrExportDeclaration::ImportDeclaration(declaration) => {
|
||||
self.visit_import_declaration(declaration);
|
||||
}
|
||||
ImportOrExportDeclaration::ExportAllDeclaration(declaration) => {
|
||||
self.visit_export_all_declaration(declaration);
|
||||
}
|
||||
ImportOrExportDeclaration::ExportDefaultDeclaration(declaration) => {
|
||||
self.visit_export_default_declaration(declaration);
|
||||
}
|
||||
ImportOrExportDeclaration::ExportNamedDeclaration(declaration) => {
|
||||
self.visit_export_named_declaration(declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_import_declaration(&mut self, declaration: &'ast ImportDeclaration) {
|
||||
self.visit_lvalue(|visitor| {
|
||||
for specifier in &declaration.specifiers {
|
||||
visitor.visit_import_declaration_specifier(specifier);
|
||||
}
|
||||
});
|
||||
self.visit_import_source(&declaration.source);
|
||||
}
|
||||
|
||||
fn visit_export_all_declaration(&mut self, declaration: &'ast ExportAllDeclaration) {
|
||||
self.visit_export_source(&declaration.source);
|
||||
}
|
||||
|
||||
fn visit_export_default_declaration(&mut self, declaration: &'ast ExportDefaultDeclaration) {
|
||||
match &declaration.declaration {
|
||||
DeclarationOrExpression::Declaration(declaration) => {
|
||||
self.visit_declaration(declaration)
|
||||
}
|
||||
DeclarationOrExpression::Expression(declaration) => self.visit_expression(declaration),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_export_named_declaration(&mut self, declaration: &'ast ExportNamedDeclaration) {
|
||||
if let Some(declaration) = &declaration.declaration {
|
||||
self.visit_declaration(declaration)
|
||||
}
|
||||
if let Some(source) = &declaration.source {
|
||||
self.visit_export_source(source);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_import_declaration_specifier(&mut self, specifier: &'ast ImportDeclarationSpecifier) {
|
||||
match specifier {
|
||||
ImportDeclarationSpecifier::ImportSpecifier(specifier) => {
|
||||
self.visit_identifier(&specifier.local);
|
||||
}
|
||||
ImportDeclarationSpecifier::ImportDefaultSpecifier(specifier) => {
|
||||
self.visit_identifier(&specifier.local);
|
||||
}
|
||||
ImportDeclarationSpecifier::ImportNamespaceSpecifier(specifier) => {
|
||||
self.visit_identifier(&specifier.local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_declaration(&mut self, declaration: &'ast Declaration) {
|
||||
self.default_visit_declaration(declaration);
|
||||
}
|
||||
|
||||
fn default_visit_declaration(&mut self, declaration: &'ast Declaration) {
|
||||
match declaration {
|
||||
Declaration::ClassDeclaration(declaration) => {
|
||||
self.visit_class(&declaration.class);
|
||||
}
|
||||
Declaration::FunctionDeclaration(declaration) => {
|
||||
self.visit_function_declaration(declaration);
|
||||
}
|
||||
Declaration::VariableDeclaration(declaration) => {
|
||||
for declarator in &declaration.declarations {
|
||||
self.visit_variable_declarator(declarator)
|
||||
}
|
||||
}
|
||||
Declaration::TSTypeAliasDeclaration(_declaration) => {
|
||||
todo!("visit TSTypeAliasDeclaration")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_function_declaration(&mut self, declaration: &'ast FunctionDeclaration) {
|
||||
self.visit_function(&declaration.function);
|
||||
}
|
||||
|
||||
fn visit_statement(&mut self, stmt: &'ast Statement) {
|
||||
self.default_visit_statement(stmt);
|
||||
}
|
||||
|
||||
fn default_visit_statement(&mut self, stmt: &'ast Statement) {
|
||||
match stmt {
|
||||
Statement::BlockStatement(stmt) => {
|
||||
for stmt in &stmt.body {
|
||||
self.visit_statement(stmt)
|
||||
}
|
||||
}
|
||||
Statement::BreakStatement(_stmt) => {
|
||||
// todo
|
||||
}
|
||||
Statement::ContinueStatement(_stmt) => {
|
||||
// todo
|
||||
}
|
||||
Statement::DebuggerStatement(_stmt) => {
|
||||
// todo
|
||||
}
|
||||
Statement::ClassDeclaration(stmt) => {
|
||||
self.visit_class(&stmt.class);
|
||||
}
|
||||
Statement::DoWhileStatement(stmt) => {
|
||||
self.visit_statement(&stmt.body);
|
||||
self.visit_expression(&stmt.test);
|
||||
}
|
||||
Statement::EmptyStatement(_stmt) => {
|
||||
// nothing to do
|
||||
}
|
||||
Statement::ExpressionStatement(stmt) => {
|
||||
self.visit_expression(&stmt.expression);
|
||||
}
|
||||
Statement::ForInStatement(stmt) => {
|
||||
self.visit_for_in_init(&stmt.left);
|
||||
self.visit_expression(&stmt.right);
|
||||
self.visit_statement(&stmt.body);
|
||||
}
|
||||
Statement::ForOfStatement(stmt) => {
|
||||
self.visit_for_in_init(&stmt.left);
|
||||
self.visit_expression(&stmt.right);
|
||||
self.visit_statement(&stmt.body);
|
||||
}
|
||||
Statement::ForStatement(stmt) => {
|
||||
if let Some(init) = &stmt.init {
|
||||
self.visit_for_init(init);
|
||||
}
|
||||
if let Some(test) = &stmt.test {
|
||||
self.visit_expression(test);
|
||||
}
|
||||
if let Some(update) = &stmt.update {
|
||||
self.visit_expression(update);
|
||||
}
|
||||
self.visit_statement(&stmt.body);
|
||||
}
|
||||
Statement::FunctionDeclaration(stmt) => {
|
||||
self.visit_function_declaration(stmt);
|
||||
}
|
||||
Statement::IfStatement(stmt) => {
|
||||
self.visit_expression(&stmt.test);
|
||||
self.visit_statement(&stmt.consequent);
|
||||
if let Some(alternate) = &stmt.alternate {
|
||||
self.visit_statement(alternate);
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(stmt) => {
|
||||
self.visit_statement(&stmt.body);
|
||||
}
|
||||
Statement::ReturnStatement(stmt) => {
|
||||
if let Some(argument) = &stmt.argument {
|
||||
self.visit_expression(argument);
|
||||
}
|
||||
}
|
||||
Statement::SwitchStatement(stmt) => {
|
||||
self.visit_expression(&stmt.discriminant);
|
||||
for case_ in &stmt.cases {
|
||||
self.visit_case(case_);
|
||||
}
|
||||
}
|
||||
Statement::ThrowStatement(stmt) => {
|
||||
self.visit_expression(&stmt.argument);
|
||||
}
|
||||
Statement::TryStatement(stmt) => {
|
||||
for item in &stmt.block.body {
|
||||
self.visit_statement(item);
|
||||
}
|
||||
if let Some(handler) = &stmt.handler {
|
||||
if let Some(param) = &handler.param {
|
||||
self.visit_lvalue(|visitor| visitor.visit_pattern(param));
|
||||
}
|
||||
for item in &handler.body.body {
|
||||
self.visit_statement(item);
|
||||
}
|
||||
}
|
||||
if let Some(finalizer) = &stmt.finalizer {
|
||||
for item in &finalizer.body {
|
||||
self.visit_statement(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::VariableDeclaration(stmt) => {
|
||||
for decl in &stmt.declarations {
|
||||
self.visit_variable_declarator(decl);
|
||||
}
|
||||
}
|
||||
Statement::WhileStatement(stmt) => {
|
||||
self.visit_expression(&stmt.test);
|
||||
self.visit_statement(&stmt.body);
|
||||
}
|
||||
Statement::WithStatement(stmt) => {
|
||||
self.visit_expression(&stmt.object);
|
||||
self.visit_statement(&stmt.body);
|
||||
}
|
||||
Statement::TSTypeAliasDeclaration(_stmt) => {
|
||||
todo!("visit TSTypeAliasDeclaration")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_class(&mut self, class: &'ast Class) {
|
||||
if let Some(id) = &class.id {
|
||||
self.visit_identifier(id)
|
||||
}
|
||||
if let Some(super_class) = &class.super_class {
|
||||
self.visit_expression(super_class);
|
||||
}
|
||||
for item in &class.body.body {
|
||||
match item {
|
||||
ClassItem::MethodDefinition(item) => self.visit_method_definition(item),
|
||||
ClassItem::ClassProperty(item) => {
|
||||
self.visit_class_property(item);
|
||||
}
|
||||
ClassItem::ClassPrivateProperty(item) => {
|
||||
self.visit_class_private_property(item);
|
||||
}
|
||||
ClassItem::StaticBlock(item) => {
|
||||
self.visit_static_block(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_class_property(&mut self, property: &'ast ClassProperty) {
|
||||
self.visit_expression(&property.key);
|
||||
if let Some(value) = &property.value {
|
||||
self.visit_expression(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_class_private_property(&mut self, property: &'ast ClassPrivateProperty) {
|
||||
match &property.key {
|
||||
ExpressionOrPrivateIdentifier::Expression(key) => self.visit_expression(key),
|
||||
ExpressionOrPrivateIdentifier::PrivateIdentifier(key) => {
|
||||
self.visit_private_identifier(key)
|
||||
}
|
||||
ExpressionOrPrivateIdentifier::PrivateName(key) => self.visit_private_name(key),
|
||||
}
|
||||
if let Some(value) = &property.value {
|
||||
self.visit_expression(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_static_block(&mut self, property: &'ast StaticBlock) {
|
||||
for stmt in &property.body {
|
||||
self.visit_statement(stmt)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_method_definition(&mut self, method: &'ast MethodDefinition) {
|
||||
self.default_visit_method_definition(method);
|
||||
}
|
||||
|
||||
fn default_visit_method_definition(&mut self, method: &'ast MethodDefinition) {
|
||||
self.visit_expression(&method.key);
|
||||
self.visit_function(&method.value.function);
|
||||
}
|
||||
|
||||
fn visit_case(&mut self, case_: &'ast SwitchCase) {
|
||||
if let Some(test) = &case_.test {
|
||||
self.visit_expression(test);
|
||||
}
|
||||
for stmt in &case_.consequent {
|
||||
self.visit_statement(stmt)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_for_init(&mut self, init: &'ast ForInit) {
|
||||
match init {
|
||||
ForInit::Expression(init) => {
|
||||
self.visit_expression(init);
|
||||
}
|
||||
ForInit::VariableDeclaration(init) => {
|
||||
for decl in &init.declarations {
|
||||
self.visit_variable_declarator(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_for_in_init(&mut self, init: &'ast ForInInit) {
|
||||
match init {
|
||||
ForInInit::Pattern(init) => {
|
||||
self.visit_pattern(init);
|
||||
}
|
||||
ForInInit::VariableDeclaration(init) => {
|
||||
for decl in &init.declarations {
|
||||
self.visit_variable_declarator(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_pattern(&mut self, pattern: &'ast Pattern) {
|
||||
match pattern {
|
||||
Pattern::Identifier(pattern) => self.visit_identifier(pattern),
|
||||
Pattern::ArrayPattern(pattern) => {
|
||||
for element in &pattern.elements {
|
||||
if let Some(element) = element {
|
||||
self.visit_pattern(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
Pattern::ObjectPattern(pattern) => {
|
||||
for property in &pattern.properties {
|
||||
match property {
|
||||
AssignmentPropertyOrRestElement::AssignmentProperty(property) => {
|
||||
self.visit_pattern(&property.value);
|
||||
}
|
||||
AssignmentPropertyOrRestElement::RestElement(property) => {
|
||||
self.visit_pattern(&property.argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Pattern::RestElement(pattern) => self.visit_pattern(&pattern.argument),
|
||||
Pattern::AssignmentPattern(pattern) => {
|
||||
self.visit_pattern(&pattern.left);
|
||||
self.visit_rvalue(|visitor| {
|
||||
visitor.visit_expression(&pattern.right);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_variable_declarator(&mut self, decl: &'ast VariableDeclarator) {
|
||||
self.visit_lvalue(|visitor| {
|
||||
visitor.visit_pattern(&decl.id);
|
||||
});
|
||||
if let Some(init) = &decl.init {
|
||||
self.visit_expression(init);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_assignment_target(&mut self, target: &'ast AssignmentTarget) {
|
||||
match target {
|
||||
AssignmentTarget::Expression(target) => {
|
||||
self.visit_expression(target);
|
||||
}
|
||||
AssignmentTarget::Pattern(target) => self.visit_pattern(target),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_expression(&mut self, expr: &'ast Expression) {
|
||||
self.default_visit_expression(expr);
|
||||
}
|
||||
|
||||
fn default_visit_expression(&mut self, expr: &'ast Expression) {
|
||||
match expr {
|
||||
Expression::ArrayExpression(expr) => {
|
||||
for item in &expr.elements {
|
||||
match item {
|
||||
Some(ExpressionOrSpread::SpreadElement(item)) => {
|
||||
self.visit_expression(&item.argument)
|
||||
}
|
||||
Some(ExpressionOrSpread::Expression(item)) => self.visit_expression(item),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::AssignmentExpression(expr) => {
|
||||
self.visit_lvalue(|visitor| visitor.visit_assignment_target(&expr.left));
|
||||
self.visit_expression(&expr.right);
|
||||
}
|
||||
Expression::BinaryExpression(expr) => {
|
||||
self.visit_expression(&expr.left);
|
||||
self.visit_expression(&expr.right);
|
||||
}
|
||||
Expression::Identifier(expr) => {
|
||||
self.visit_identifier(expr);
|
||||
}
|
||||
Expression::Literal(expr) => self.visit_literal(expr),
|
||||
Expression::FunctionExpression(expr) => self.visit_function(&expr.function),
|
||||
Expression::ArrowFunctionExpression(expr) => self.visit_function(&expr.function),
|
||||
Expression::MemberExpression(expr) => {
|
||||
match &expr.object {
|
||||
ExpressionOrSuper::Super(object) => self.visit_super(object),
|
||||
ExpressionOrSuper::Expression(object) => self.visit_expression(object),
|
||||
};
|
||||
if !expr.is_computed {
|
||||
match &expr.property {
|
||||
ExpressionOrPrivateIdentifier::Expression(property) => {
|
||||
self.visit_expression(property)
|
||||
}
|
||||
ExpressionOrPrivateIdentifier::PrivateIdentifier(property) => {
|
||||
self.visit_private_identifier(property);
|
||||
}
|
||||
ExpressionOrPrivateIdentifier::PrivateName(property) => {
|
||||
self.visit_private_name(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::CallExpression(expr) => {
|
||||
match &expr.callee {
|
||||
ExpressionOrSuper::Expression(callee) => self.visit_expression(callee),
|
||||
ExpressionOrSuper::Super(callee) => self.visit_super(callee),
|
||||
}
|
||||
for arg in &expr.arguments {
|
||||
match arg {
|
||||
ExpressionOrSpread::Expression(arg) => self.visit_expression(arg),
|
||||
ExpressionOrSpread::SpreadElement(arg) => {
|
||||
self.visit_expression(&arg.argument)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::UpdateExpression(expr) => {
|
||||
self.visit_expression(&expr.argument);
|
||||
}
|
||||
Expression::BooleanLiteral(_)
|
||||
| Expression::NullLiteral(_)
|
||||
| Expression::StringLiteral(_)
|
||||
| Expression::NumericLiteral(_) => {
|
||||
// no-op
|
||||
}
|
||||
_ => {
|
||||
todo!("{:#?}", expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_super(&mut self, _super: &'ast Super) {
|
||||
todo!("Implement visit_super")
|
||||
}
|
||||
|
||||
fn visit_private_identifier(&mut self, _identifier: &'ast PrivateIdentifier) {
|
||||
todo!("Implement visit_private_identifier()")
|
||||
}
|
||||
|
||||
fn visit_private_name(&mut self, _identifier: &'ast PrivateName) {
|
||||
todo!("Implement visit_private_name()")
|
||||
}
|
||||
|
||||
fn visit_identifier(&mut self, _identifier: &'ast Identifier) {
|
||||
todo!("Implement visit_identifier()")
|
||||
}
|
||||
|
||||
fn visit_import_source(&mut self, literal: &'ast _Literal) {
|
||||
self.visit_any_literal(literal);
|
||||
}
|
||||
|
||||
fn visit_export_source(&mut self, literal: &'ast _Literal) {
|
||||
self.visit_any_literal(literal);
|
||||
}
|
||||
|
||||
fn visit_any_literal(&mut self, _literal: &'ast _Literal) {
|
||||
todo!("Implement visit_any_literal()")
|
||||
}
|
||||
|
||||
fn visit_literal(&mut self, _literal: &'ast Literal) {
|
||||
todo!("Implement visit_literal()")
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
[package]
|
||||
name = "react_estree_codegen"
|
||||
version = "0.1.0"
|
||||
publish = false
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
indexmap = { workspace = true }
|
||||
prettyplease = { workspace = true }
|
||||
quote = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
syn = { workspace = true }
|
||||
@@ -1,4 +0,0 @@
|
||||
# react_estree_codegen
|
||||
|
||||
This crate is a build dependency for `react_estree`, and contains codegen logic to produce Rust code to describe the ESTree format
|
||||
given a JSON schema.
|
||||
@@ -1,969 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use quote::__private::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use syn::Type;
|
||||
|
||||
/// Returns prettyplease-formatted Rust source for estree
|
||||
pub fn estree() -> String {
|
||||
let src = include_str!("./ecmascript.json");
|
||||
let grammar: Grammar = serde_json::from_str(src).unwrap();
|
||||
let raw = grammar.codegen().to_string();
|
||||
|
||||
let parsed = syn::parse_file(&raw).unwrap();
|
||||
format!(
|
||||
"// {}generated\n#![cfg_attr(rustfmt, rustfmt_skip)]\n{}",
|
||||
'\u{0040}',
|
||||
prettyplease::unparse(&parsed)
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns prettyplease-formatted Rust source for converting HermesParser results
|
||||
/// into estree
|
||||
pub fn estree_hermes() -> String {
|
||||
let src = include_str!("./ecmascript.json");
|
||||
let grammar: Grammar = serde_json::from_str(src).unwrap();
|
||||
let raw = grammar.codegen_hermes().to_string();
|
||||
|
||||
let parsed = syn::parse_file(&raw).unwrap();
|
||||
format!(
|
||||
"// {}generated\n#![cfg_attr(rustfmt, rustfmt_skip)]\n{}",
|
||||
'\u{0040}',
|
||||
prettyplease::unparse(&parsed)
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Grammar {
|
||||
pub objects: IndexMap<String, Object>,
|
||||
pub nodes: IndexMap<String, Node>,
|
||||
pub enums: IndexMap<String, Enum>,
|
||||
pub operators: IndexMap<String, Operator>,
|
||||
}
|
||||
|
||||
impl Grammar {
|
||||
pub fn codegen(self) -> TokenStream {
|
||||
let object_defs: Vec<_> = self
|
||||
.objects
|
||||
.iter()
|
||||
.map(|(name, object)| object.codegen(name))
|
||||
.collect();
|
||||
let object_visitors: Vec<_> = self
|
||||
.objects
|
||||
.iter()
|
||||
.filter_map(|(name, object)| {
|
||||
if object.visitor {
|
||||
Some(object.codegen_visitor(name, &self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let node_defs: Vec<_> = self
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|(name, node)| node.codegen(name))
|
||||
.collect();
|
||||
let node_visitors: Vec<_> = self
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|(name, node)| node.codegen_visitor(name, &self))
|
||||
.collect();
|
||||
let enum_defs: Vec<_> = self
|
||||
.enums
|
||||
.iter()
|
||||
.map(|(name, enum_)| enum_.codegen(name, &self.enums))
|
||||
.collect();
|
||||
let enum_visitors: Vec<_> = self
|
||||
.enums
|
||||
.iter()
|
||||
.map(|(name, enum_)| enum_.codegen_visitor(name))
|
||||
.collect();
|
||||
let operator_defs: Vec<_> = self
|
||||
.operators
|
||||
.iter()
|
||||
.map(|(name, operator)| operator.codegen(name))
|
||||
.collect();
|
||||
|
||||
quote! {
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(clippy::enum_variant_names)]
|
||||
|
||||
use std::num::NonZeroU32;
|
||||
use serde::ser::{Serializer, SerializeMap};
|
||||
use serde::{Serialize,Deserialize};
|
||||
use crate::{JsValue, Binding, SourceRange, Number, ESTreeNode};
|
||||
|
||||
#(#object_defs)*
|
||||
|
||||
#(#node_defs)*
|
||||
|
||||
#(#enum_defs)*
|
||||
|
||||
#(#operator_defs)*
|
||||
|
||||
pub trait Visitor {
|
||||
#(#object_visitors)*
|
||||
|
||||
#(#node_visitors)*
|
||||
|
||||
#(#enum_visitors)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_hermes(self) -> TokenStream {
|
||||
let nodes: Vec<_> = self
|
||||
.nodes
|
||||
.iter()
|
||||
.filter(|(_, node)| !node.skip_hermes_codegen)
|
||||
.map(|(name, node)| node.codegen_hermes(name))
|
||||
.collect();
|
||||
let enums: Vec<_> = self
|
||||
.enums
|
||||
.iter()
|
||||
.map(|(name, enum_)| enum_.codegen_hermes(name, &self))
|
||||
.collect();
|
||||
let operators: Vec<_> = self
|
||||
.operators
|
||||
.iter()
|
||||
.map(|(name, operator)| operator.codegen_hermes(name))
|
||||
.collect();
|
||||
|
||||
quote! {
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(clippy::enum_variant_names)]
|
||||
|
||||
use react_estree::*;
|
||||
use hermes::parser::{NodePtr, NodeKind, NodeLabel };
|
||||
use hermes::utf::{utf8_with_surrogates_to_string};
|
||||
use crate::generated_extension::*;
|
||||
|
||||
#(#nodes)*
|
||||
|
||||
#(#enums)*
|
||||
|
||||
#(#operators)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Object {
|
||||
#[serde(default)]
|
||||
pub fields: IndexMap<String, Field>,
|
||||
|
||||
#[serde(default)]
|
||||
pub visitor: bool,
|
||||
}
|
||||
|
||||
impl Object {
|
||||
pub fn codegen(&self, name: &str) -> TokenStream {
|
||||
let name = format_ident!("{}", name);
|
||||
let fields: Vec<_> = self
|
||||
.fields
|
||||
.iter()
|
||||
.map(|(name, field)| field.codegen(name))
|
||||
.collect();
|
||||
|
||||
quote! {
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct #name {
|
||||
#(#fields),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_visitor(&self, name: &str, grammar: &Grammar) -> TokenStream {
|
||||
let visitor_name = format_ident!("visit_{}", to_lower_snake_case(name));
|
||||
let name = format_ident!("{}", name);
|
||||
let field_visitors: Vec<_> = self
|
||||
.fields
|
||||
.iter()
|
||||
.filter_map(|(name, field)| {
|
||||
let (type_name_str, type_kind) = parse_type(&field.type_).unwrap();
|
||||
if !grammar.nodes.contains_key(&type_name_str)
|
||||
&& !grammar.enums.contains_key(&type_name_str)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let visitor_name = format_ident!("visit_{}", to_lower_snake_case(&type_name_str));
|
||||
let field_name = format_ident!("{}", name);
|
||||
Some(match type_kind {
|
||||
TypeKind::Named => {
|
||||
quote! {
|
||||
self.#visitor_name(&ast.#field_name);
|
||||
}
|
||||
}
|
||||
TypeKind::Option => {
|
||||
quote! {
|
||||
if let Some(#field_name) = &ast.#field_name {
|
||||
self.#visitor_name(#field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeKind::Vec => {
|
||||
quote! {
|
||||
for #field_name in &ast.#field_name {
|
||||
self.#visitor_name(#field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeKind::VecOfOption => {
|
||||
quote! {
|
||||
for #field_name in &ast.#field_name {
|
||||
if let Some(#field_name) = #field_name {
|
||||
self.#visitor_name(#field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
quote! {
|
||||
fn #visitor_name(&mut self, ast: &#name) {
|
||||
#(#field_visitors)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Node {
|
||||
#[serde(default)]
|
||||
#[serde(rename = "type")]
|
||||
pub type_: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub fields: IndexMap<String, Field>,
|
||||
|
||||
#[serde(default)]
|
||||
pub skip_hermes_codegen: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub skip_hermes_enum_variant: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(rename = "TODO")]
|
||||
pub todo: Option<String>,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
pub fn codegen(&self, name: &str) -> TokenStream {
|
||||
let name_str = name;
|
||||
let name = format_ident!("{}", name);
|
||||
let fields: Vec<_> = self
|
||||
.fields
|
||||
.iter()
|
||||
.map(|(name, field)| field.codegen_node(name))
|
||||
.collect();
|
||||
|
||||
let type_serializer = if let Some(type_) = &self.type_ {
|
||||
quote! {
|
||||
state.serialize_entry("type", #type_)?;
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
state.serialize_entry("type", #name_str)?;
|
||||
}
|
||||
};
|
||||
|
||||
let mut field_serializers = Vec::with_capacity(self.fields.len()); // type, loc, range
|
||||
for (field_name_str, field) in &self.fields {
|
||||
if field.skip {
|
||||
continue;
|
||||
}
|
||||
let field_name = format_ident!("{}", field_name_str);
|
||||
let serialized_field_name = field.rename.as_ref().unwrap_or(field_name_str);
|
||||
let serializer = if field.flatten {
|
||||
quote! {
|
||||
Serialize::serialize(&self.#field_name, serde::__private::ser::FlatMapSerializer(&mut state))?;
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
state.serialize_entry(#serialized_field_name, &self.#field_name)?;
|
||||
}
|
||||
};
|
||||
field_serializers.push(serializer);
|
||||
}
|
||||
|
||||
quote! {
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
pub struct #name {
|
||||
#(#fields,)*
|
||||
|
||||
#[serde(default)]
|
||||
pub loc: Option<SourceLocation>,
|
||||
|
||||
#[serde(default)]
|
||||
pub range: Option<SourceRange>,
|
||||
}
|
||||
|
||||
impl ESTreeNode for #name {}
|
||||
|
||||
impl Serialize for #name {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_map(None)?;
|
||||
#type_serializer
|
||||
#(#field_serializers)*
|
||||
state.serialize_entry("loc", &self.loc)?;
|
||||
state.serialize_entry("range", &self.range)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_visitor(&self, name: &str, grammar: &Grammar) -> TokenStream {
|
||||
let visitor_name = format_ident!("visit_{}", to_lower_snake_case(name));
|
||||
let name = format_ident!("{}", name);
|
||||
let field_visitors: Vec<_> = self
|
||||
.fields
|
||||
.iter()
|
||||
.filter_map(|(name, field)| {
|
||||
let (type_name_str, type_kind) = parse_type(&field.type_).unwrap();
|
||||
if (!grammar.objects.contains_key(&type_name_str)
|
||||
|| !grammar.objects.get(&type_name_str).unwrap().visitor)
|
||||
&& !grammar.nodes.contains_key(&type_name_str)
|
||||
&& !grammar.enums.contains_key(&type_name_str)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let visitor_name = format_ident!("visit_{}", to_lower_snake_case(&type_name_str));
|
||||
let field_name = format_ident!("{}", name);
|
||||
Some(match type_kind {
|
||||
TypeKind::Named => {
|
||||
quote! {
|
||||
self.#visitor_name(&ast.#field_name);
|
||||
}
|
||||
}
|
||||
TypeKind::Option => {
|
||||
quote! {
|
||||
if let Some(#field_name) = &ast.#field_name {
|
||||
self.#visitor_name(#field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeKind::Vec => {
|
||||
quote! {
|
||||
for #field_name in &ast.#field_name {
|
||||
self.#visitor_name(#field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeKind::VecOfOption => {
|
||||
quote! {
|
||||
for #field_name in &ast.#field_name {
|
||||
if let Some(#field_name) = #field_name {
|
||||
self.#visitor_name(#field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
quote! {
|
||||
fn #visitor_name(&mut self, ast: &#name) {
|
||||
#(#field_visitors)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_hermes(&self, name: &str) -> TokenStream {
|
||||
let name_str = name;
|
||||
let name = format_ident!("{}", name);
|
||||
let field_names: Vec<_> = self
|
||||
.fields
|
||||
.iter()
|
||||
.map(|(name, _field)| format_ident!("{}", name))
|
||||
.collect();
|
||||
let fields: Vec<_> = self
|
||||
.fields
|
||||
.iter()
|
||||
.map(|(name, field)| {
|
||||
let (type_name_str, type_kind) = parse_type(&field.type_).unwrap();
|
||||
let camelcase_name = field.rename.as_ref().unwrap_or(name);
|
||||
let field_name = format_ident!("{}", name);
|
||||
let helper = format_ident!("hermes_get_{}_{}", name_str, camelcase_name);
|
||||
let type_name = format_ident!("{}", type_name_str);
|
||||
if field.skip || field.hermes_default {
|
||||
return quote! {
|
||||
let #field_name = Default::default();
|
||||
};
|
||||
}
|
||||
if let Some(convert_with) = &field.hermes_convert_with {
|
||||
let convert_with = format_ident!("{}", convert_with);
|
||||
return quote! {
|
||||
let #field_name = #convert_with(cx, unsafe { hermes::parser::#helper(node) } );
|
||||
}
|
||||
}
|
||||
match type_kind {
|
||||
TypeKind::Named => {
|
||||
match type_name_str.as_ref() {
|
||||
"bool" => {
|
||||
quote! {
|
||||
let #field_name = unsafe { hermes::parser::#helper(node) };
|
||||
}
|
||||
}
|
||||
"Number" => {
|
||||
quote! {
|
||||
let #field_name = convert_number(unsafe { hermes::parser::#helper(node) });
|
||||
}
|
||||
}
|
||||
"String" => {
|
||||
quote! {
|
||||
let #field_name = convert_string(cx, unsafe { hermes::parser::#helper(node) });
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
quote! {
|
||||
let #field_name = #type_name::convert(cx, unsafe { hermes::parser::#helper(node) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeKind::Option => {
|
||||
match type_name_str.as_ref() {
|
||||
"String" => {
|
||||
quote! {
|
||||
let #field_name = convert_option_string(cx, unsafe { hermes::parser::#helper(node) });
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
quote! {
|
||||
let #field_name = convert_option(unsafe { hermes::parser::#helper(node) }, |node| #type_name::convert(cx, node));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeKind::Vec => {
|
||||
quote! {
|
||||
let #field_name = convert_vec(unsafe { hermes::parser::#helper(node) }, |node| #type_name::convert(cx, node));
|
||||
}
|
||||
}
|
||||
TypeKind::VecOfOption => {
|
||||
quote! {
|
||||
let #field_name = convert_vec_of_option(unsafe { hermes::parser::#helper(node) }, |node| #type_name::convert(cx, node));
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let type_ = format_ident!("{}", self.type_.as_ref().unwrap_or(&name_str.to_string()));
|
||||
quote! {
|
||||
impl FromHermes for #name {
|
||||
fn convert(cx: &mut Context, node: NodePtr) -> Self {
|
||||
let node_ref = node.as_ref();
|
||||
assert_eq!(node_ref.kind, NodeKind::#type_);
|
||||
let range = convert_range(cx, node);
|
||||
#(#fields)*
|
||||
Self {
|
||||
#(#field_names,)*
|
||||
loc: None,
|
||||
range: Some(range),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Field {
|
||||
// TODO: deserialize with `parse_type` into a custom type
|
||||
#[serde(rename = "type")]
|
||||
pub type_: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub optional: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub flatten: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub rename: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub skip: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(rename = "TODO")]
|
||||
pub todo: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub hermes_convert_with: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub hermes_default: bool,
|
||||
}
|
||||
|
||||
impl Field {
|
||||
pub fn codegen(&self, name: &str) -> TokenStream {
|
||||
let name = format_ident!("{}", name);
|
||||
parse_type(&self.type_).unwrap();
|
||||
let type_name: Type = syn::parse_str(&self.type_)
|
||||
.unwrap_or_else(|_| panic!("Expected a type name, got `{}`", &self.type_));
|
||||
|
||||
let type_ = quote!(#type_name);
|
||||
let mut field = quote!(pub #name: #type_);
|
||||
if self.optional {
|
||||
field = quote! {
|
||||
#[serde(default)]
|
||||
#field
|
||||
}
|
||||
}
|
||||
if self.flatten {
|
||||
field = quote! {
|
||||
#[serde(flatten)]
|
||||
#field
|
||||
}
|
||||
}
|
||||
if self.skip {
|
||||
field = quote! {
|
||||
#[serde(skip)]
|
||||
#field
|
||||
}
|
||||
}
|
||||
if let Some(rename) = &self.rename {
|
||||
field = quote! {
|
||||
#[serde(rename = #rename)]
|
||||
#field
|
||||
}
|
||||
}
|
||||
field
|
||||
}
|
||||
|
||||
pub fn codegen_node(&self, name: &str) -> TokenStream {
|
||||
let name = format_ident!("{}", name);
|
||||
parse_type(&self.type_).unwrap();
|
||||
let type_name: Type = syn::parse_str(&self.type_)
|
||||
.unwrap_or_else(|_| panic!("Expected a type name, got `{}`", &self.type_));
|
||||
let type_ = quote!(#type_name);
|
||||
let mut field = quote!(pub #name: #type_);
|
||||
if self.optional {
|
||||
field = quote! {
|
||||
#[serde(default)]
|
||||
#field
|
||||
}
|
||||
}
|
||||
if self.flatten {
|
||||
field = quote! {
|
||||
#[serde(flatten)]
|
||||
#field
|
||||
}
|
||||
}
|
||||
if self.skip {
|
||||
field = quote! {
|
||||
#[serde(skip)]
|
||||
#field
|
||||
}
|
||||
}
|
||||
if let Some(rename) = &self.rename {
|
||||
field = quote! {
|
||||
#[serde(rename = #rename)]
|
||||
#field
|
||||
}
|
||||
}
|
||||
field
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(transparent)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Enum {
|
||||
pub variants: Vec<String>,
|
||||
}
|
||||
|
||||
impl Enum {
|
||||
pub fn codegen(&self, name: &str, enums: &IndexMap<String, Enum>) -> TokenStream {
|
||||
let mut sorted_variants: Vec<_> = self.variants.iter().collect();
|
||||
sorted_variants.sort();
|
||||
|
||||
let name_str = name;
|
||||
let name = format_ident!("{}", name);
|
||||
let variants: Vec<_> = sorted_variants
|
||||
.iter()
|
||||
.map(|name| {
|
||||
let variant = format_ident!("{}", name);
|
||||
if enums.contains_key(*name) {
|
||||
quote!(#variant(#variant))
|
||||
} else {
|
||||
quote!(#variant(Box<#variant>))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let enum_tag = format_ident!("__{}Tag", name);
|
||||
let mut seen = HashSet::new();
|
||||
|
||||
// tag_variants is used to generate an enum of all the possible type tags (`type` values)
|
||||
// that can appear in this enum. we emit this enum and derive a deserializer for it so that
|
||||
// our enum deserializer can first decode the tag in order to know how to decode the data
|
||||
let mut tag_variants = Vec::new();
|
||||
|
||||
// once the tag is decoded, we need to match against it and deserialize according the tag (`type`)
|
||||
// tag_matches are the match arms for each type.
|
||||
let mut tag_matches = Vec::new();
|
||||
|
||||
// Imagine a case like:
|
||||
// enum ModuleItem {
|
||||
// ImportDeclaration, // struct
|
||||
// Statement // another enum
|
||||
// }
|
||||
// We need to generate matches for all the possible *concrete* `type` values, which means
|
||||
// we have to expand nested enums such as `Statement`
|
||||
for variant in self.variants.iter() {
|
||||
if let Some(nested_enum) = enums.get(variant) {
|
||||
let outer_variant = format_ident!("{}", variant);
|
||||
for variant in nested_enum.variants.iter() {
|
||||
// Skip variants that appear in multiple nested enums, we deserialize
|
||||
// as the first listed outer variant
|
||||
if !seen.insert(variant.to_string()) {
|
||||
continue;
|
||||
}
|
||||
// Modeling ESTree only requires a single level of nested enums,
|
||||
// so that's all we support. Though in theory we could support arbitrary nesting,
|
||||
// since ultimately we're matching based on the final concrete types.
|
||||
assert!(!enums.contains_key(variant));
|
||||
|
||||
let inner_variant = format_ident!("{}", variant);
|
||||
tag_variants.push(quote!(#inner_variant));
|
||||
|
||||
tag_matches.push(quote! {
|
||||
#enum_tag::#inner_variant => {
|
||||
let node: Box<#inner_variant> = <Box<#inner_variant> as Deserialize>::deserialize(
|
||||
serde::__private::de::ContentDeserializer::<D::Error>::new(tagged.1),
|
||||
)?;
|
||||
Ok(#name::#outer_variant(#outer_variant::#inner_variant(node)))
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if !seen.insert(variant.to_string()) {
|
||||
panic!(
|
||||
"Concrete variant {} was already added by a nested enum",
|
||||
variant
|
||||
);
|
||||
}
|
||||
let variant_name = format_ident!("{}", variant);
|
||||
tag_variants.push(quote!(#variant_name));
|
||||
|
||||
tag_matches.push(quote! {
|
||||
#enum_tag::#variant_name => {
|
||||
let node: Box<#variant_name> = <Box<#variant_name> as Deserialize>::deserialize(
|
||||
serde::__private::de::ContentDeserializer::<D::Error>::new(tagged.1),
|
||||
)?;
|
||||
Ok(#name::#variant_name(node))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
quote! {
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
#[serde(untagged)]
|
||||
pub enum #name {
|
||||
#(#variants),*
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
enum #enum_tag {
|
||||
#(#tag_variants),*
|
||||
}
|
||||
|
||||
impl <'de> serde::Deserialize<'de> for #name {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: serde::Deserializer<'de> {
|
||||
let tagged = serde::Deserializer::deserialize_any(
|
||||
deserializer,
|
||||
serde::__private::de::TaggedContentVisitor::<#enum_tag>::new("type", #name_str)
|
||||
)?;
|
||||
match tagged.0 {
|
||||
#(#tag_matches),*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_visitor(&self, name: &str) -> TokenStream {
|
||||
let visitor_name = format_ident!("visit_{}", to_lower_snake_case(name));
|
||||
let name = format_ident!("{}", name);
|
||||
let mut tag_matches = Vec::new();
|
||||
|
||||
for variant in self.variants.iter() {
|
||||
let node_variant = format_ident!("{}", variant);
|
||||
let visitor_name = format_ident!("visit_{}", to_lower_snake_case(variant));
|
||||
|
||||
tag_matches.push(quote! {
|
||||
#name::#node_variant(ast) => {
|
||||
self.#visitor_name(ast);
|
||||
}
|
||||
})
|
||||
}
|
||||
quote! {
|
||||
fn #visitor_name(&mut self, ast: &#name) {
|
||||
match ast {
|
||||
#(#tag_matches),*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_hermes(&self, name: &str, grammar: &Grammar) -> TokenStream {
|
||||
let name_str = name;
|
||||
let name = format_ident!("{}", name);
|
||||
|
||||
let mut tag_matches = Vec::new();
|
||||
let mut seen = HashSet::new();
|
||||
|
||||
// Imagine a case like:
|
||||
// enum ModuleItem {
|
||||
// ImportDeclaration, // struct
|
||||
// Statement // another enum
|
||||
// }
|
||||
// We need to generate matches for all the possible *concrete* `type` values, which means
|
||||
// we have to expand nested enums such as `Statement`
|
||||
for variant in self.variants.iter() {
|
||||
if let Some(nested_enum) = grammar.enums.get(variant) {
|
||||
let outer_variant = format_ident!("{}", variant);
|
||||
for variant in nested_enum.variants.iter() {
|
||||
// Skip variants that appear in multiple nested enums, we deserialize
|
||||
// as the first listed outer variant
|
||||
if !seen.insert(variant.to_string()) {
|
||||
continue;
|
||||
}
|
||||
// Modeling ESTree only requires a single level of nested enums,
|
||||
// so that's all we support. Though in theory we could support arbitrary nesting,
|
||||
// since ultimately we're matching based on the final concrete types.
|
||||
assert!(!grammar.enums.contains_key(variant));
|
||||
let node = grammar.nodes.get(variant).unwrap();
|
||||
if node.skip_hermes_enum_variant {
|
||||
continue;
|
||||
}
|
||||
|
||||
let inner_variant = format_ident!("{}", variant);
|
||||
let node_variant_name = node.type_.as_ref().unwrap_or(variant);
|
||||
let node_variant = format_ident!("{}", node_variant_name);
|
||||
|
||||
tag_matches.push(quote! {
|
||||
NodeKind::#node_variant => {
|
||||
let node = #inner_variant::convert(cx, node);
|
||||
#name::#outer_variant(#outer_variant::#inner_variant(Box::new(node)))
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if !seen.insert(variant.to_string()) {
|
||||
panic!(
|
||||
"Concrete variant {} was already added by a nested enum",
|
||||
variant
|
||||
);
|
||||
}
|
||||
let variant_name = format_ident!("{}", variant);
|
||||
let node = grammar.nodes.get(variant).unwrap();
|
||||
if node.skip_hermes_enum_variant {
|
||||
continue;
|
||||
}
|
||||
|
||||
let node_variant_name = node.type_.as_ref().unwrap_or(variant);
|
||||
let node_variant = format_ident!("{}", node_variant_name);
|
||||
|
||||
tag_matches.push(quote! {
|
||||
NodeKind::#node_variant => {
|
||||
let node = #variant_name::convert(cx, node);
|
||||
#name::#variant_name(Box::new(node))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
quote! {
|
||||
impl FromHermes for #name {
|
||||
fn convert(cx: &mut Context, node: NodePtr) -> Self {
|
||||
let node_ref = node.as_ref();
|
||||
match node_ref.kind {
|
||||
#(#tag_matches),*
|
||||
_ => panic!("Unexpected node kind `{:?}` for `{}`", node_ref.kind, #name_str)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(transparent)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Operator {
|
||||
pub variants: IndexMap<String, String>,
|
||||
}
|
||||
|
||||
impl Operator {
|
||||
pub fn codegen(&self, name: &str) -> TokenStream {
|
||||
let mut sorted_variants: Vec<_> = self.variants.iter().collect();
|
||||
sorted_variants.sort();
|
||||
|
||||
let name = format_ident!("{}", name);
|
||||
let variants: Vec<_> = sorted_variants
|
||||
.iter()
|
||||
.map(|(name, operator)| {
|
||||
let name = format_ident!("{}", name);
|
||||
let comment = format!(" {}", &operator);
|
||||
quote! {
|
||||
#[doc = #comment]
|
||||
#[serde(rename = #operator)]
|
||||
#name
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let display_matches: Vec<_> = sorted_variants
|
||||
.iter()
|
||||
.map(|(name, operator)| {
|
||||
let name = format_ident!("{}", name);
|
||||
quote!(Self::#name => #operator)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let fromstr_matches: Vec<_> = sorted_variants
|
||||
.iter()
|
||||
.map(|(name, operator)| {
|
||||
let name = format_ident!("{}", name);
|
||||
quote!(#operator => Ok(Self::#name))
|
||||
})
|
||||
.collect();
|
||||
|
||||
quote! {
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||
pub enum #name {
|
||||
#(#variants),*
|
||||
}
|
||||
|
||||
impl std::fmt::Display for #name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let name = match self {
|
||||
#(#display_matches),*
|
||||
};
|
||||
f.write_str(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for #name {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
#(#fromstr_matches,)*
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_hermes(&self, name: &str) -> TokenStream {
|
||||
let mut sorted_variants: Vec<_> = self.variants.iter().collect();
|
||||
sorted_variants.sort();
|
||||
|
||||
let name = format_ident!("{}", name);
|
||||
|
||||
quote! {
|
||||
impl FromHermesLabel for #name {
|
||||
fn convert(cx: &mut Context, label: NodeLabel) -> Self {
|
||||
let utf_str = utf8_with_surrogates_to_string(label.as_slice()).unwrap();
|
||||
utf_str.parse().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum TypeKind {
|
||||
/// T
|
||||
Named,
|
||||
|
||||
/// Option<T>
|
||||
Option,
|
||||
|
||||
/// Vec<T>
|
||||
Vec,
|
||||
|
||||
/// Vec<Option<T>>
|
||||
VecOfOption,
|
||||
}
|
||||
|
||||
/// Parses a given type into the underlying type name plus a descriptor of the
|
||||
/// kind of type. Only a subset of Rust types are supported:
|
||||
/// - T
|
||||
/// - Option<T>
|
||||
/// - Vec<T>
|
||||
/// - Vec<Option<T>>
|
||||
fn parse_type(type_: &str) -> Result<(String, TypeKind), String> {
|
||||
let mut current = type_;
|
||||
let mut is_list = false;
|
||||
let mut is_option = false;
|
||||
if current.starts_with("Vec<") {
|
||||
current = ¤t[4..current.len() - 1];
|
||||
is_list = true;
|
||||
}
|
||||
if current.starts_with("Option<") {
|
||||
current = ¤t[7..current.len() - 1];
|
||||
is_option = true;
|
||||
}
|
||||
if current.contains('<') {
|
||||
Err(format!(
|
||||
"Unsupported type `{current}` expected named type (`Identifier`), optional type (`Option<Identifier>`), list type (`Vec<Identifier>`), or optional list (`Vec<Option<Identifier>>`)"
|
||||
))
|
||||
} else {
|
||||
let kind = match (is_list, is_option) {
|
||||
(true, true) => TypeKind::VecOfOption,
|
||||
(true, false) => TypeKind::Vec,
|
||||
(false, true) => TypeKind::Option,
|
||||
(false, false) => TypeKind::Named,
|
||||
};
|
||||
Ok((current.to_string(), kind))
|
||||
}
|
||||
}
|
||||
|
||||
// from https://github.com/rust-lang/rust-analyzer/blob/4105378dc7479a3dbd39a4afb3eba67d083bd7f8/xtask/src/codegen/gen_syntax.rs#L406C1-L418C2
|
||||
fn to_lower_snake_case(s: &str) -> String {
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
let mut prev = false;
|
||||
for c in s.chars() {
|
||||
if c.is_ascii_uppercase() {
|
||||
if prev {
|
||||
buf.push('_')
|
||||
}
|
||||
prev = false;
|
||||
} else {
|
||||
prev = true;
|
||||
}
|
||||
|
||||
buf.push(c.to_ascii_lowercase());
|
||||
}
|
||||
buf
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
mod codegen;
|
||||
|
||||
pub use codegen::{estree, estree_hermes};
|
||||
@@ -1,24 +0,0 @@
|
||||
[package]
|
||||
name = "react_fixtures"
|
||||
version = "0.1.0"
|
||||
publish = false
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { workspace = true }
|
||||
react_estree = { workspace = true }
|
||||
react_hermes_parser = { workspace = true }
|
||||
react_hir = { workspace = true }
|
||||
react_optimization = { workspace = true }
|
||||
react_semantic_analysis = { workspace = true }
|
||||
react_ssa = { workspace = true }
|
||||
react_build_hir = { workspace = true }
|
||||
miette = { workspace = true, features = ["backtrace", "fancy"] }
|
||||
@@ -1,3 +0,0 @@
|
||||
# fixtures
|
||||
|
||||
This crate is for tests only, and runs the suite of compiler fixture tests.
|
||||
@@ -1,6 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
@@ -1,34 +0,0 @@
|
||||
function Component() {
|
||||
let a = 1;
|
||||
|
||||
let b;
|
||||
if (a === 1) {
|
||||
b = true;
|
||||
} else {
|
||||
b = false;
|
||||
}
|
||||
|
||||
let c;
|
||||
if (b) {
|
||||
c = "hello";
|
||||
} else {
|
||||
c = null;
|
||||
}
|
||||
|
||||
let d;
|
||||
if (c === "hello") {
|
||||
d = 42.0;
|
||||
} else {
|
||||
d = 42.001;
|
||||
}
|
||||
|
||||
let e;
|
||||
if (d === 42.0) {
|
||||
e = "ok";
|
||||
} else {
|
||||
e = "nope";
|
||||
}
|
||||
|
||||
// should constant-propagate to "ok"
|
||||
return e;
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
function Component(props) {
|
||||
// global propagation
|
||||
let a;
|
||||
a = Math;
|
||||
a; // Math
|
||||
|
||||
// primitive propagation w phi
|
||||
let b;
|
||||
if (props) {
|
||||
b = true;
|
||||
} else {
|
||||
b = true;
|
||||
}
|
||||
b; // true
|
||||
|
||||
// primitive propagation fails if different values
|
||||
let c;
|
||||
if (props) {
|
||||
c = true;
|
||||
} else {
|
||||
c = 42;
|
||||
}
|
||||
c; // <no change>
|
||||
|
||||
// constant evaluation
|
||||
42 + 1; // 43
|
||||
42 - 1; // 41
|
||||
42 * 2; // 84
|
||||
42 / 2; // 21
|
||||
0 == 1; // false
|
||||
0 != 1; // true
|
||||
0 === 1; // false
|
||||
0 !== 1; // true
|
||||
0 == 0; // true
|
||||
// TODO: unary operators
|
||||
// 0 == -0; // false
|
||||
// 0 != -0; // true
|
||||
// 0 === -0; // false
|
||||
// 0 !== -0; // true
|
||||
NaN == NaN; // false
|
||||
NaN != NaN; // true
|
||||
NaN !== NaN; // true
|
||||
NaN !== NaN; // true
|
||||
"hello" == "hello"; // true
|
||||
"hello" != "hello"; // false
|
||||
"hello" === "hello"; // true
|
||||
"hello" !== "hello"; // false
|
||||
"hello" == "world"; // false
|
||||
"hello" != "world"; // true
|
||||
"hello" === "world"; // false
|
||||
"hello" !== "world"; // true
|
||||
true == true; // true
|
||||
true != true; // false
|
||||
true === true; // true
|
||||
true !== true; // false
|
||||
|
||||
// constant evaluation through variable
|
||||
let x = 5 * 60 * 60 * 1000; // 5 hours in milliseconds
|
||||
x;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
function Component(a, b) {
|
||||
const [c, , ...d] = a;
|
||||
const [[[e]], ...[f]] = b;
|
||||
return [c, d, e, f];
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
function Component(a, b) {
|
||||
const {
|
||||
c,
|
||||
d,
|
||||
e: { e },
|
||||
f: { _f: f },
|
||||
g: {
|
||||
g: {
|
||||
g: { g, ...h },
|
||||
},
|
||||
},
|
||||
...i
|
||||
} = a;
|
||||
return [c, d, e, f, g, h, i];
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
function foo() {
|
||||
x = true;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
function foo() {
|
||||
let x = 0;
|
||||
for (let i = 0; i < 10; i = i + 1) {
|
||||
x = x + i;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
function Component(props) {
|
||||
const x = 2;
|
||||
const foo = function foo(y) {
|
||||
let a = 1;
|
||||
let b;
|
||||
if (a === 1) {
|
||||
b = 5 + 3;
|
||||
} else {
|
||||
b = false;
|
||||
}
|
||||
x + y + a + b;
|
||||
const bar = function bar(z) {
|
||||
let c = 2;
|
||||
let d;
|
||||
d = 3;
|
||||
x + y + a + b + z + c + d;
|
||||
};
|
||||
bar;
|
||||
foo;
|
||||
};
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// import React from "react";
|
||||
|
||||
// const FOO = false;
|
||||
|
||||
function id(x) {
|
||||
// React;
|
||||
// FOO;
|
||||
Math;
|
||||
id;
|
||||
let y = true;
|
||||
y = false;
|
||||
y;
|
||||
let z;
|
||||
z;
|
||||
return x;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
function foo(a, b, c, d) {
|
||||
if (a) {
|
||||
return b;
|
||||
} else {
|
||||
c;
|
||||
}
|
||||
d;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
function Component(a) {
|
||||
Math;
|
||||
let b = 0;
|
||||
const foo = function foo_(c) {
|
||||
let d = 1;
|
||||
return a + b + c + d;
|
||||
};
|
||||
return foo();
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
function Component(props) {
|
||||
let a;
|
||||
if (props) {
|
||||
a = 1;
|
||||
} else {
|
||||
a = 2;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
function test() {
|
||||
[true, false, null, 1, 3.14, ...["hello world!"]];
|
||||
return 2;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
function Component(a, b) {
|
||||
let x;
|
||||
let y = 0;
|
||||
let z = 10;
|
||||
if (a) {
|
||||
x = 1;
|
||||
if (b) {
|
||||
z = 20;
|
||||
} else {
|
||||
z = 30;
|
||||
}
|
||||
} else {
|
||||
x = 2;
|
||||
}
|
||||
return x + y + z;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { useMemo } from "react";
|
||||
|
||||
function Component(x) {
|
||||
const y = useMemo(() => {
|
||||
return x;
|
||||
});
|
||||
return y;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use std::env;
|
||||
use std::fmt::Write;
|
||||
|
||||
use insta::{assert_snapshot, glob};
|
||||
use miette::{NamedSource, Report};
|
||||
use react_build_hir::build;
|
||||
use react_estree::{ModuleItem, Statement};
|
||||
use react_hermes_parser::parse;
|
||||
use react_hir::{inline_use_memo, Environment, Features, Print, Registry};
|
||||
use react_optimization::constant_propagation;
|
||||
use react_semantic_analysis::analyze;
|
||||
use react_ssa::{eliminate_redundant_phis, enter_ssa};
|
||||
|
||||
#[test]
|
||||
fn fixtures() {
|
||||
glob!("fixtures/**.js", |path| {
|
||||
println!("fixture {}", path.to_str().unwrap());
|
||||
let input = std::fs::read_to_string(path).unwrap();
|
||||
let ast = parse(&input, path.to_str().unwrap()).unwrap();
|
||||
println!("ok parse");
|
||||
|
||||
let mut output = String::new();
|
||||
|
||||
let mut analysis = analyze(&ast, Default::default());
|
||||
let diagnostics = analysis.diagnostics();
|
||||
if !diagnostics.is_empty() {
|
||||
for diagnostic in diagnostics {
|
||||
eprintln!(
|
||||
"{:?}",
|
||||
Report::new(diagnostic)
|
||||
.with_source_code(NamedSource::new(path.to_string_lossy(), input.clone(),))
|
||||
);
|
||||
}
|
||||
}
|
||||
let environment = Environment::new(
|
||||
Features {
|
||||
validate_frozen_lambdas: true,
|
||||
},
|
||||
Registry,
|
||||
analysis,
|
||||
);
|
||||
for (ix, item) in ast.body.iter().enumerate() {
|
||||
if let ModuleItem::Statement(stmt) = item {
|
||||
if let Statement::FunctionDeclaration(fun) = stmt {
|
||||
if ix != 0 {
|
||||
output.push_str("\n\n");
|
||||
}
|
||||
match build(&environment, &fun.function) {
|
||||
Ok(mut fun) => {
|
||||
println!("ok build");
|
||||
enter_ssa(&environment, &mut fun).unwrap();
|
||||
println!("ok enter_ssa");
|
||||
eliminate_redundant_phis(&environment, &mut fun);
|
||||
println!("ok eliminate_redundant_phis");
|
||||
constant_propagation(&environment, &mut fun).unwrap();
|
||||
println!("ok constant_propagation");
|
||||
inline_use_memo(&environment, &mut fun).unwrap();
|
||||
println!("ok inline_use_memo");
|
||||
fun.print(&fun.body, &mut output).unwrap();
|
||||
println!("ok print");
|
||||
}
|
||||
Err(error) => {
|
||||
write!(&mut output, "{}", error,).unwrap();
|
||||
eprintln!(
|
||||
"{:?}",
|
||||
Report::new(error).with_source_code(NamedSource::new(
|
||||
path.to_string_lossy(),
|
||||
input.clone(),
|
||||
))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let output = output.trim();
|
||||
assert_snapshot!(format!("Input:\n{input}\n\nOutput:\n{output}"));
|
||||
});
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
---
|
||||
source: crates/react_fixtures/tests/fixtures_test.rs
|
||||
expression: "format!(\"Input:\\n{input}\\n\\nOutput:\\n{output}\")"
|
||||
input_file: crates/react_fixtures/tests/fixtures/constant-propagation-constant-if-condition.js
|
||||
---
|
||||
Input:
|
||||
function Component() {
|
||||
let a = 1;
|
||||
|
||||
let b;
|
||||
if (a === 1) {
|
||||
b = true;
|
||||
} else {
|
||||
b = false;
|
||||
}
|
||||
|
||||
let c;
|
||||
if (b) {
|
||||
c = "hello";
|
||||
} else {
|
||||
c = null;
|
||||
}
|
||||
|
||||
let d;
|
||||
if (c === "hello") {
|
||||
d = 42.0;
|
||||
} else {
|
||||
d = 42.001;
|
||||
}
|
||||
|
||||
let e;
|
||||
if (d === 42.0) {
|
||||
e = "ok";
|
||||
} else {
|
||||
e = "nope";
|
||||
}
|
||||
|
||||
// should constant-propagate to "ok"
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
Output:
|
||||
function Component(
|
||||
)
|
||||
entry bb0
|
||||
bb0 (block)
|
||||
[0] unknown $39 = 1
|
||||
[1] unknown $41 = StoreLocal Let unknown a$40 = unknown $39
|
||||
[2] unknown $43 = DeclareLocal Let unknown b$42
|
||||
[3] unknown $44 = 1
|
||||
[4] unknown $45 = 1
|
||||
[5] unknown $46 = true
|
||||
[6] unknown $47 = true
|
||||
[7] unknown $49 = StoreLocal Reassign unknown b$48 = unknown $47
|
||||
[8] unknown $54 = DeclareLocal Let unknown c$53
|
||||
[9] unknown $56 = true
|
||||
[10] unknown $57 = "hello"
|
||||
[11] unknown $59 = StoreLocal Reassign unknown c$58 = unknown $57
|
||||
[12] unknown $64 = DeclareLocal Let unknown d$63
|
||||
[13] unknown $66 = "hello"
|
||||
[14] unknown $67 = "hello"
|
||||
[15] unknown $68 = true
|
||||
[16] unknown $69 = 42
|
||||
[17] unknown $71 = StoreLocal Reassign unknown d$70 = unknown $69
|
||||
[18] unknown $76 = DeclareLocal Let unknown e$75
|
||||
[19] unknown $78 = 42
|
||||
[20] unknown $79 = 42
|
||||
[21] unknown $80 = true
|
||||
[22] unknown $81 = "ok"
|
||||
[23] unknown $83 = StoreLocal Reassign unknown e$82 = unknown $81
|
||||
[24] unknown $88 = "ok"
|
||||
[25] Return unknown $88
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user