Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b817b78bc |
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"packages": ["packages/react", "packages/react-dom", "packages/react-server-dom-webpack", "packages/scheduler"],
|
||||
"packages": ["packages/react", "packages/react-dom", "packages/scheduler"],
|
||||
"buildCommand": "download-build-in-codesandbox-ci",
|
||||
"node": "18",
|
||||
"publishDirectory": {
|
||||
"react": "build/oss-experimental/react",
|
||||
"react-dom": "build/oss-experimental/react-dom",
|
||||
"react-server-dom-webpack": "build/oss-experimental/react-server-dom-webpack",
|
||||
"scheduler": "build/oss-experimental/scheduler"
|
||||
},
|
||||
"sandboxes": ["new"],
|
||||
|
||||
36
.eslintrc.js
36
.eslintrc.js
@@ -446,7 +446,10 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['scripts/eslint-rules/*.js'],
|
||||
files: [
|
||||
'scripts/eslint-rules/*.js',
|
||||
'packages/eslint-plugin-react-hooks/src/*.js',
|
||||
],
|
||||
plugins: ['eslint-plugin'],
|
||||
rules: {
|
||||
'eslint-plugin/prefer-object-rule': ERROR,
|
||||
@@ -493,11 +496,9 @@ 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',
|
||||
@@ -505,7 +506,6 @@ module.exports = {
|
||||
__IS_EDGE__: 'readonly',
|
||||
__IS_NATIVE__: 'readonly',
|
||||
__IS_INTERNAL_VERSION__: 'readonly',
|
||||
chrome: 'readonly',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -514,26 +514,6 @@ 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: {
|
||||
@@ -609,14 +589,6 @@ module.exports = {
|
||||
WheelEventHandler: 'readonly',
|
||||
FinalizationRegistry: 'readonly',
|
||||
Omit: 'readonly',
|
||||
Keyframe: 'readonly',
|
||||
PropertyIndexedKeyframes: 'readonly',
|
||||
KeyframeAnimationOptions: 'readonly',
|
||||
GetAnimationsOptions: 'readonly',
|
||||
Animatable: 'readonly',
|
||||
ScrollTimeline: 'readonly',
|
||||
EventListenerOptionsOrUseCapture: 'readonly',
|
||||
FocusOptions: 'readonly',
|
||||
|
||||
spyOnDev: 'readonly',
|
||||
spyOnDevAndProd: 'readonly',
|
||||
|
||||
18
.github/ISSUE_TEMPLATE/19.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/19.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: "⚛React 19 beta issue"
|
||||
about: Report a issue with React 19 beta.
|
||||
title: '[React 19]'
|
||||
labels: 'React 19'
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
<!--
|
||||
Please provide a CodeSandbox (https://codesandbox.io/s/new), a link to a
|
||||
repository on GitHub, or provide a minimal code example that reproduces the
|
||||
problem. You may provide a screenshot of the application if you think it is
|
||||
relevant to your bug report. Here are some tips for providing a minimal
|
||||
example: https://stackoverflow.com/help/mcve.
|
||||
-->
|
||||
47
.github/workflows/compiler_discord_notify.yml
vendored
47
.github/workflows/compiler_discord_notify.yml
vendored
@@ -1,47 +0,0 @@
|
||||
name: (Compiler) Discord Notify
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, ready_for_review]
|
||||
paths:
|
||||
- compiler/**
|
||||
- .github/workflows/compiler_**.yml
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
check_access:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }}
|
||||
steps:
|
||||
- name: Check is member or collaborator
|
||||
id: check_is_member_or_collaborator
|
||||
if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }}
|
||||
run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
check_maintainer:
|
||||
if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }}
|
||||
needs: [check_access]
|
||||
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,8 +8,6 @@ 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
|
||||
@@ -38,27 +36,10 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-and-playground-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ 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()'
|
||||
@@ -68,4 +49,3 @@ jobs:
|
||||
with:
|
||||
name: test-results
|
||||
path: compiler/apps/playground/test-results
|
||||
if-no-files-found: ignore
|
||||
|
||||
14
.github/workflows/compiler_prereleases.yml
vendored
14
.github/workflows/compiler_prereleases.yml
vendored
@@ -16,19 +16,15 @@ on:
|
||||
version_name:
|
||||
required: true
|
||||
type: string
|
||||
tag_version:
|
||||
required: false
|
||||
type: string
|
||||
secrets:
|
||||
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:
|
||||
@@ -50,12 +46,10 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ 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
|
||||
scripts/release/publish.js --frfr --ci --versionName=${{ inputs.version_name }} --tag=${{ inputs.dist_tag }} ${{ inputs.tag_version && format('--tagVersion={0}', inputs.tag_version) || '' }}
|
||||
scripts/release/publish.js --frfr --ci --versionName=${{ inputs.version_name }} --tag ${{ inputs.dist_tag }}
|
||||
|
||||
@@ -14,11 +14,6 @@ on:
|
||||
version_name:
|
||||
required: true
|
||||
type: string
|
||||
tag_version:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
@@ -32,6 +27,5 @@ jobs:
|
||||
release_channel: ${{ inputs.release_channel }}
|
||||
dist_tag: ${{ inputs.dist_tag }}
|
||||
version_name: ${{ inputs.version_name }}
|
||||
tag_version: ${{ inputs.tag_version }}
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
@@ -5,8 +5,6 @@ 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
|
||||
|
||||
|
||||
21
.github/workflows/compiler_prereleases_weekly.yml
vendored
Normal file
21
.github/workflows/compiler_prereleases_weekly.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: (Compiler) Publish Prereleases Weekly
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# At 10 minutes past 9:00 on Mon
|
||||
- cron: 10 9 * * 1
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
jobs:
|
||||
publish_prerelease_beta:
|
||||
name: Publish to beta channel
|
||||
uses: facebook/react/.github/workflows/compiler_prereleases.yml@main
|
||||
with:
|
||||
commit_sha: ${{ github.sha }}
|
||||
release_channel: beta
|
||||
dist_tag: beta
|
||||
version_name: '19.0.0'
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
77
.github/workflows/compiler_rust.yml
vendored
Normal file
77
.github/workflows/compiler_rust.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
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,8 +8,6 @@ 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
|
||||
@@ -47,13 +45,10 @@ 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-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ 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
|
||||
@@ -71,19 +66,17 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ 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:
|
||||
@@ -97,12 +90,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ 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,8 +9,6 @@ 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
|
||||
@@ -20,9 +18,6 @@ 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
|
||||
@@ -34,15 +29,13 @@ jobs:
|
||||
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') }}
|
||||
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
|
||||
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: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
- name: Download react-devtools artifacts for base revision
|
||||
run: |
|
||||
git fetch origin main
|
||||
@@ -54,7 +47,6 @@ jobs:
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
if-no-files-found: error
|
||||
|
||||
build_devtools_and_process_artifacts:
|
||||
name: Build DevTools and process artifacts
|
||||
@@ -71,13 +63,11 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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:
|
||||
@@ -93,27 +83,23 @@ 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"
|
||||
@@ -122,6 +108,7 @@ jobs:
|
||||
- "17.0"
|
||||
- "18.0"
|
||||
- "18.2" # compiler polyfill
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@@ -133,11 +120,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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
|
||||
@@ -150,7 +135,6 @@ jobs:
|
||||
needs: build_devtools_and_process_artifacts
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version:
|
||||
- "16.0"
|
||||
@@ -158,6 +142,7 @@ jobs:
|
||||
- "16.8" # hooks
|
||||
- "17.0"
|
||||
- "18.0"
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@@ -169,28 +154,17 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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: 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'
|
||||
- name: Playwright install deps
|
||||
run: |
|
||||
npx playwright install
|
||||
sudo npx playwright install-deps
|
||||
- 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 }}
|
||||
@@ -202,4 +176,3 @@ jobs:
|
||||
with:
|
||||
name: screenshots
|
||||
path: ./tmp/screenshots
|
||||
if-no-files-found: warn
|
||||
|
||||
447
.github/workflows/runtime_build_and_test.yml
vendored
447
.github/workflows/runtime_build_and_test.yml
vendored
@@ -7,8 +7,6 @@ on:
|
||||
paths-ignore:
|
||||
- compiler/**
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
@@ -19,95 +17,6 @@ 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
|
||||
@@ -127,10 +36,10 @@ jobs:
|
||||
|
||||
flow:
|
||||
name: Flow check ${{ matrix.flow_inline_config_shortname }}
|
||||
needs: [discover_flow_inline_configs, runtime_node_modules_cache]
|
||||
needs: discover_flow_inline_configs
|
||||
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:
|
||||
@@ -143,25 +52,19 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
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-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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/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
|
||||
@@ -173,19 +76,14 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
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-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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 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)
|
||||
@@ -193,7 +91,6 @@ jobs:
|
||||
# ----- FEATURE FLAGS -----
|
||||
flags:
|
||||
name: Check flags
|
||||
needs: [runtime_node_modules_cache]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -205,25 +102,21 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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"
|
||||
@@ -251,6 +144,7 @@ jobs:
|
||||
- 3/5
|
||||
- 4/5
|
||||
- 5/5
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -259,37 +153,26 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@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') }}
|
||||
restore-keys: |
|
||||
runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-and-compiler-node_modules-v6-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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 --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,20,21,22,23,24]
|
||||
worker_id: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
|
||||
release_channel: [stable, experimental]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -299,30 +182,21 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
cache-dependency-path: yarn.lock
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11.0.22
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@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') }}
|
||||
restore-keys: |
|
||||
runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-and-compiler-node_modules-v6-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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 --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
|
||||
- run: yarn build --index=${{ matrix.worker_id }} --total=20 --r=${{ matrix.release_channel }} --ci
|
||||
env:
|
||||
CI: github
|
||||
RELEASE_CHANNEL: ${{ matrix.release_channel }}
|
||||
@@ -336,13 +210,11 @@ 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, runtime_compiler_node_modules_cache]
|
||||
needs: build_and_lint
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test_params: [
|
||||
# Intentionally passing these as strings instead of creating a
|
||||
@@ -375,16 +247,10 @@ jobs:
|
||||
# TODO: Test more persistent configurations?
|
||||
]
|
||||
shard:
|
||||
- 1/10
|
||||
- 2/10
|
||||
- 3/10
|
||||
- 4/10
|
||||
- 5/10
|
||||
- 6/10
|
||||
- 7/10
|
||||
- 8/10
|
||||
- 9/10
|
||||
- 10/10
|
||||
- 1/3
|
||||
- 2/3
|
||||
- 3/3
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -394,25 +260,16 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@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') }}
|
||||
restore-keys: |
|
||||
runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-
|
||||
runtime-and-compiler-node_modules-v6-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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 --cwd compiler install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -425,11 +282,7 @@ jobs:
|
||||
|
||||
process_artifacts_combined:
|
||||
name: Process artifacts combined
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
permissions:
|
||||
# https://github.com/actions/attest-build-provenance
|
||||
id-token: write
|
||||
attestations: write
|
||||
needs: build_and_lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -441,19 +294,14 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
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-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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:
|
||||
@@ -462,7 +310,7 @@ jobs:
|
||||
merge-multiple: true
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA
|
||||
- run: echo ${{ github.sha }} >> build/COMMIT_SHA
|
||||
- name: Scrape warning messages
|
||||
run: |
|
||||
mkdir -p ./build/__test_utils__
|
||||
@@ -472,29 +320,16 @@ 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, runtime_node_modules_cache]
|
||||
needs: build_and_lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -506,19 +341,14 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
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-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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:
|
||||
@@ -534,7 +364,7 @@ jobs:
|
||||
|
||||
check_release_dependencies:
|
||||
name: Check release dependencies
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
needs: build_and_lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -546,19 +376,14 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
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-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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:
|
||||
@@ -583,16 +408,16 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: fixtures_dom-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'fixtures/dom/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: fixtures_dom-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn --cwd fixtures/dom install --frozen-lockfile
|
||||
if: steps.node_modules.outputs.cache-hit != 'true'
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
|
||||
working-directory: fixtures/dom
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -627,31 +452,14 @@ 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 # note: this does not reuse centralized cache since it has unique cache key
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: fixtures_flight-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'fixtures/flight/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: fixtures_flight-node_modules-${{ 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 --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:
|
||||
@@ -660,6 +468,18 @@ 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
|
||||
@@ -671,23 +491,17 @@ 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, runtime_node_modules_cache]
|
||||
needs: build_and_lint
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
browser: [chrome, firefox, edge]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -698,52 +512,45 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
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-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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:
|
||||
pattern: _build_*
|
||||
path: build
|
||||
merge-multiple: true
|
||||
- run: ./scripts/ci/pack_and_store_devtools_artifacts.sh ${{ matrix.browser }}
|
||||
- run: ./scripts/ci/pack_and_store_devtools_artifacts.sh
|
||||
env:
|
||||
RELEASE_CHANNEL: experimental
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
# Simplifies getting the extension for local testing
|
||||
- name: Archive ${{ matrix.browser }} extension
|
||||
- name: Archive devtools build
|
||||
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
|
||||
pattern: react-devtools-*-extension
|
||||
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
|
||||
|
||||
run_devtools_e2e_tests:
|
||||
name: Run DevTools e2e tests
|
||||
needs: [build_and_lint, runtime_node_modules_cache]
|
||||
needs: build_devtools_and_process_artifacts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -755,19 +562,14 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
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-
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ 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:
|
||||
@@ -782,13 +584,9 @@ jobs:
|
||||
RELEASE_CHANNEL: experimental
|
||||
|
||||
# ----- SIZEBOT -----
|
||||
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]
|
||||
permissions:
|
||||
# We use github.token to download the build artifact from a previous runtime_build_and_test.yml run
|
||||
actions: read
|
||||
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
|
||||
@@ -800,36 +598,57 @@ jobs:
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4 # note: this does not reuse centralized cache since it has unique cache key
|
||||
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') }}
|
||||
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
|
||||
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: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
- 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') || ''}}
|
||||
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
|
||||
# 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
|
||||
- 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:
|
||||
name: Run sizebot
|
||||
needs: [build_and_lint, 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: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build for PR
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -842,11 +661,17 @@ jobs:
|
||||
node ./scripts/print-warnings/print-warnings.js > build/__test_utils__/ReactAllWarnings.js
|
||||
- name: Display structure of build for PR
|
||||
run: ls -R build
|
||||
- run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA
|
||||
- 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: 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,13 +16,6 @@ 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
|
||||
@@ -32,40 +25,6 @@ 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 }}
|
||||
@@ -105,11 +64,27 @@ 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"
|
||||
- name: Restore downloaded build
|
||||
uses: actions/download-artifact@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
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: Display structure of build
|
||||
run: ls -R build
|
||||
- name: Strip @license from eslint plugin and react-refresh
|
||||
@@ -132,10 +107,9 @@ 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 eslint-plugin-react-hooks
|
||||
mkdir ./compiled/eslint-plugin-react-hooks
|
||||
# Move eslint-plugin-react-hooks into facebook-www
|
||||
mv build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \
|
||||
./compiled/eslint-plugin-react-hooks/index.js
|
||||
./compiled/facebook-www/eslint-plugin-react-hooks.js
|
||||
|
||||
# Move unstable_server-external-runtime.js into facebook-www
|
||||
mv build/oss-experimental/react-dom/unstable_server-external-runtime.js \
|
||||
@@ -173,9 +147,9 @@ jobs:
|
||||
ls -R ./compiled-rn
|
||||
- name: Add REVISION files
|
||||
run: |
|
||||
echo ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} >> ./compiled/facebook-www/REVISION
|
||||
echo ${{ github.sha }} >> ./compiled/facebook-www/REVISION
|
||||
cp ./compiled/facebook-www/REVISION ./compiled/facebook-www/REVISION_TRANSFORMS
|
||||
echo ${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} >> ./compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION
|
||||
echo ${{ github.sha}} >> ./compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION
|
||||
- name: "Get current version string"
|
||||
id: get_current_version
|
||||
run: |
|
||||
@@ -192,20 +166,15 @@ 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, process_artifacts]
|
||||
if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.process_artifacts.outputs.www_branch_count == '0')
|
||||
needs: download_artifacts
|
||||
if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.download_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:
|
||||
@@ -217,12 +186,12 @@ jobs:
|
||||
name: compiled
|
||||
path: compiled/
|
||||
- name: Revert version changes
|
||||
if: needs.process_artifacts.outputs.last_version_classic != '' && needs.process_artifacts.outputs.last_version_modern != ''
|
||||
if: needs.download_artifacts.outputs.last_version_classic != '' && needs.download_artifacts.outputs.last_version_modern != ''
|
||||
env:
|
||||
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 }}
|
||||
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 }}
|
||||
run: |
|
||||
echo "Reverting $CURRENT_VERSION_CLASSIC to $LAST_VERSION_CLASSIC"
|
||||
grep -rl "$CURRENT_VERSION_CLASSIC" ./compiled || echo "No files found with $CURRENT_VERSION_CLASSIC"
|
||||
@@ -252,12 +221,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.process_artifacts.outputs.last_version_classic != '' && needs.process_artifacts.outputs.last_version_modern != '')
|
||||
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 != '')
|
||||
env:
|
||||
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 }}
|
||||
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 }}
|
||||
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"
|
||||
@@ -271,31 +240,24 @@ jobs:
|
||||
- name: Will commit these changes
|
||||
if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
|
||||
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"
|
||||
echo ":"
|
||||
git status -u
|
||||
- name: Commit changes to branch
|
||||
if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
|
||||
run: |
|
||||
git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}"
|
||||
git config --global user.name "${{ github.triggering_actor }}"
|
||||
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) }}
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
commit_fbsource_artifacts:
|
||||
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')
|
||||
needs: download_artifacts
|
||||
if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.download_artifacts.outputs.fbsource_branch_count == '0')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -308,10 +270,10 @@ jobs:
|
||||
name: compiled-rn
|
||||
path: compiled-rn/
|
||||
- name: Revert version changes
|
||||
if: needs.process_artifacts.outputs.last_version_rn != ''
|
||||
if: needs.download_artifacts.outputs.last_version_rn != ''
|
||||
env:
|
||||
CURRENT_VERSION: ${{ needs.process_artifacts.outputs.current_version_rn }}
|
||||
LAST_VERSION: ${{ needs.process_artifacts.outputs.last_version_rn }}
|
||||
CURRENT_VERSION: ${{ needs.download_artifacts.outputs.current_version_rn }}
|
||||
LAST_VERSION: ${{ needs.download_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"
|
||||
@@ -337,10 +299,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.process_artifacts.outputs.last_version_rn != '')
|
||||
if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_rn != '')
|
||||
env:
|
||||
CURRENT_VERSION: ${{ needs.process_artifacts.outputs.current_version_rn }}
|
||||
LAST_VERSION: ${{ needs.process_artifacts.outputs.last_version_rn }}
|
||||
CURRENT_VERSION: ${{ needs.download_artifacts.outputs.current_version_rn }}
|
||||
LAST_VERSION: ${{ needs.download_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"
|
||||
@@ -447,19 +409,15 @@ 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'
|
||||
run: |
|
||||
git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}"
|
||||
git config --global user.name "${{ github.triggering_actor }}"
|
||||
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) }}
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
47
.github/workflows/runtime_discord_notify.yml
vendored
47
.github/workflows/runtime_discord_notify.yml
vendored
@@ -1,47 +0,0 @@
|
||||
name: (Runtime) Discord Notify
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, ready_for_review]
|
||||
paths-ignore:
|
||||
- compiler/**
|
||||
- .github/workflows/compiler_**.yml
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
check_access:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }}
|
||||
steps:
|
||||
- name: Check is member or collaborator
|
||||
id: check_is_member_or_collaborator
|
||||
if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }}
|
||||
run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
check_maintainer:
|
||||
if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }}
|
||||
needs: [check_access]
|
||||
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.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 }}
|
||||
65
.github/workflows/runtime_eslint_plugin_e2e.yml
vendored
65
.github/workflows/runtime_eslint_plugin_e2e.yml
vendored
@@ -1,65 +0,0 @@
|
||||
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,8 +8,6 @@ on:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
|
||||
35
.github/workflows/runtime_prereleases.yml
vendored
35
.github/workflows/runtime_prereleases.yml
vendored
@@ -13,34 +13,21 @@ on:
|
||||
dist_tag:
|
||||
required: true
|
||||
type: string
|
||||
enableFailureNotification:
|
||||
description: 'Whether to notify the team on Discord when the release fails. Useful if this workflow is called from an automation.'
|
||||
required: false
|
||||
type: boolean
|
||||
secrets:
|
||||
DISCORD_WEBHOOK_URL:
|
||||
description: 'Discord webhook URL to notify on failure. Only required if enableFailureNotification is true.'
|
||||
required: false
|
||||
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
|
||||
@@ -52,24 +39,14 @@ jobs:
|
||||
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') }}
|
||||
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
|
||||
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: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
- run: |
|
||||
GH_TOKEN=${{ secrets.GH_TOKEN }} scripts/release/prepare-release-from-ci.js --skipTests -r ${{ inputs.release_channel }} --commit=${{ inputs.commit_sha }}
|
||||
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 }}
|
||||
- name: Notify Discord on failure
|
||||
if: failure() && inputs.enableFailureNotification == true
|
||||
uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
|
||||
with:
|
||||
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
embed-author-name: "GitHub Actions"
|
||||
embed-title: 'Publish of $${{ inputs.release_channel }} release failed'
|
||||
embed-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }}
|
||||
|
||||
10
.github/workflows/runtime_prereleases_manual.yml
vendored
10
.github/workflows/runtime_prereleases_manual.yml
vendored
@@ -6,8 +6,6 @@ on:
|
||||
prerelease_commit_sha:
|
||||
required: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
@@ -16,9 +14,6 @@ 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
|
||||
@@ -35,14 +30,10 @@ 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
|
||||
@@ -54,4 +45,3 @@ jobs:
|
||||
dist_tag: experimental
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -5,8 +5,6 @@ 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
|
||||
|
||||
@@ -14,25 +12,16 @@ 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
|
||||
enableFailureNotification: true
|
||||
secrets:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
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
|
||||
@@ -42,8 +31,5 @@ jobs:
|
||||
commit_sha: ${{ github.sha }}
|
||||
release_channel: experimental
|
||||
dist_tag: experimental
|
||||
enableFailureNotification: true
|
||||
secrets:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
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
58
.github/workflows/shared_check_maintainer.yml
vendored
@@ -1,58 +0,0 @@
|
||||
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;
|
||||
@@ -1,41 +0,0 @@
|
||||
# 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
|
||||
@@ -1,36 +0,0 @@
|
||||
# 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 }}
|
||||
@@ -1,42 +0,0 @@
|
||||
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'
|
||||
});
|
||||
21
.github/workflows/shared_discord_notify.yml
vendored
Normal file
21
.github/workflows/shared_discord_notify.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: (Shared) Discord Notify
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
notify:
|
||||
if: ${{ github.event.label.name == 'React Core Team' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Discord Webhook Action
|
||||
uses: tsickert/discord-webhook@v6.0.0
|
||||
with:
|
||||
webhook-url: ${{ secrets.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 }}
|
||||
54
.github/workflows/shared_label_core_team_prs.yml
vendored
54
.github/workflows/shared_label_core_team_prs.yml
vendored
@@ -1,54 +0,0 @@
|
||||
name: (Shared) Label Core Team PRs
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
|
||||
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_access:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }}
|
||||
steps:
|
||||
- name: Check is member or collaborator
|
||||
id: check_is_member_or_collaborator
|
||||
if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }}
|
||||
run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
check_maintainer:
|
||||
if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }}
|
||||
needs: [check_access]
|
||||
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,8 +5,6 @@ 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
|
||||
@@ -29,15 +27,12 @@ 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-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ 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:
|
||||
@@ -52,15 +47,12 @@ 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-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ 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:
|
||||
@@ -75,15 +67,12 @@ 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-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ 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:
|
||||
@@ -98,13 +87,10 @@ 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-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ 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,8 +6,6 @@ on:
|
||||
- cron: '0 * * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -37,4 +37,3 @@ packages/react-devtools-fusebox/dist
|
||||
packages/react-devtools-inline/dist
|
||||
packages/react-devtools-shell/dist
|
||||
packages/react-devtools-timeline/dist
|
||||
|
||||
|
||||
18
CHANGELOG-canary.md
Normal file
18
CHANGELOG-canary.md
Normal file
@@ -0,0 +1,18 @@
|
||||
## March 22, 2024 (18.3.0-canary-670811593-20240322)
|
||||
|
||||
## React
|
||||
- Added `useActionState` to replace `useFormState` and added `pending` value ([#28491](https://github.com/facebook/react/pull/28491)).
|
||||
|
||||
## October 5, 2023 (18.3.0-canary-546178f91-20231005)
|
||||
|
||||
### React
|
||||
|
||||
- Added support for async functions to be passed to `startTransition`.
|
||||
- `useTransition` now triggers the nearest error boundary instead of a global error.
|
||||
- Added `useOptimistic`, a new Hook for handling optimistic UI updates. It optimistically updates the UI before receiving confirmation from a server or external source.
|
||||
|
||||
### React DOM
|
||||
|
||||
- Added support for passing async functions to the `action` prop on `<form>`. When the function passed to `action` is marked with [`'use server'`](https://react.dev/reference/react/use-server), the form is [progressively enhanced](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement).
|
||||
- Added `useFormStatus`, a new Hook for checking the submission state of a form.
|
||||
- Added `useFormState`, a new Hook for updating state upon form submission. When the function passed to `useFormState` is marked with [`'use server'`](https://react.dev/reference/react/use-server), the update is [progressively enhanced](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement).
|
||||
47
CHANGELOG.md
47
CHANGELOG.md
@@ -1,50 +1,3 @@
|
||||
## 19.1.0 (March 28, 2025)
|
||||
|
||||
### Owner Stack
|
||||
|
||||
An Owner Stack is a string representing the components that are directly responsible for rendering a particular component. You can log Owner Stacks when debugging or use Owner Stacks to enhance error overlays or other development tools. Owner Stacks are only available in development builds. Component Stacks in production are unchanged.
|
||||
|
||||
* An Owner Stack is a development-only stack trace that helps identify which components are responsible for rendering a particular component. An Owner Stack is distinct from a Component Stacks, which shows the hierarchy of components leading to an error.
|
||||
* The [captureOwnerStack API](https://react.dev/reference/react/captureOwnerStack) is only available in development mode and returns a Owner Stack, if available. The API can be used to enhance error overlays or log component relationships when debugging. [#29923](https://github.com/facebook/react/pull/29923), [#32353](https://github.com/facebook/react/pull/32353), [#30306](https://github.com/facebook/react/pull/30306),
|
||||
[#32538](https://github.com/facebook/react/pull/32538), [#32529](https://github.com/facebook/react/pull/32529), [#32538](https://github.com/facebook/react/pull/32538)
|
||||
|
||||
### React
|
||||
* Enhanced support for Suspense boundaries to be used anywhere, including the client, server, and during hydration. [#32069](https://github.com/facebook/react/pull/32069), [#32163](https://github.com/facebook/react/pull/32163), [#32224](https://github.com/facebook/react/pull/32224), [#32252](https://github.com/facebook/react/pull/32252)
|
||||
* Reduced unnecessary client rendering through improved hydration scheduling [#31751](https://github.com/facebook/react/pull/31751)
|
||||
* Increased priority of client rendered Suspense boundaries [#31776](https://github.com/facebook/react/pull/31776)
|
||||
* Fixed frozen fallback states by rendering unfinished Suspense boundaries on the client. [#31620](https://github.com/facebook/react/pull/31620)
|
||||
* Reduced garbage collection pressure by improving Suspense boundary retries. [#31667](https://github.com/facebook/react/pull/31667)
|
||||
* Fixed erroneous “Waiting for Paint” log when the passive effect phase was not delayed [#31526](https://github.com/facebook/react/pull/31526)
|
||||
* Fixed a regression causing key warnings for flattened positional children in development mode. [#32117](https://github.com/facebook/react/pull/32117)
|
||||
* Updated `useId` to use valid CSS selectors, changing format from `:r123:` to `«r123»`. [#32001](https://github.com/facebook/react/pull/32001)
|
||||
* Added a dev-only warning for null/undefined created in useEffect, useInsertionEffect, and useLayoutEffect. [#32355](https://github.com/facebook/react/pull/32355)
|
||||
* Fixed a bug where dev-only methods were exported in production builds. React.act is no longer available in production builds. [#32200](https://github.com/facebook/react/pull/32200)
|
||||
* Improved consistency across prod and dev to improve compatibility with Google Closure Complier and bindings [#31808](https://github.com/facebook/react/pull/31808)
|
||||
* Improve passive effect scheduling for consistent task yielding. [#31785](https://github.com/facebook/react/pull/31785)
|
||||
* Fixed asserts in React Native when passChildrenWhenCloningPersistedNodes is enabled for OffscreenComponent rendering. [#32528](https://github.com/facebook/react/pull/32528)
|
||||
* Fixed component name resolution for Portal [#32640](https://github.com/facebook/react/pull/32640)
|
||||
* Added support for beforetoggle and toggle events on the dialog element. #32479 [#32479](https://github.com/facebook/react/pull/32479)
|
||||
|
||||
### React DOM
|
||||
* Fixed double warning when the `href` attribute is an empty string [#31783](https://github.com/facebook/react/pull/31783)
|
||||
* Fixed an edge case where `getHoistableRoot()` didn’t work properly when the container was a Document [#32321](https://github.com/facebook/react/pull/32321)
|
||||
* Removed support for using HTML comments (e.g. `<!-- -->`) as a DOM container. [#32250](https://github.com/facebook/react/pull/32250)
|
||||
* Added support for `<script>` and `<template>` tags to be nested within `<select>` tags. [#31837](https://github.com/facebook/react/pull/31837)
|
||||
* Fixed responsive images to be preloaded as HTML instead of headers [#32445](https://github.com/facebook/react/pull/32445)
|
||||
|
||||
### use-sync-external-store
|
||||
* Added `exports` field to `package.json` for `use-sync-external-store` to support various entrypoints. [#25231](https://github.com/facebook/react/pull/25231)
|
||||
|
||||
### React Server Components
|
||||
* Added `unstable_prerender`, a new experimental API for prerendering React Server Components on the server [#31724](https://github.com/facebook/react/pull/31724)
|
||||
* Fixed an issue where streams would hang when receiving new chunks after a global error [#31840](https://github.com/facebook/react/pull/31840), [#31851](https://github.com/facebook/react/pull/31851)
|
||||
* Fixed an issue where pending chunks were counted twice. [#31833](https://github.com/facebook/react/pull/31833)
|
||||
* Added support for streaming in edge environments [#31852](https://github.com/facebook/react/pull/31852)
|
||||
* Added support for sending custom error names from a server so that they are available in the client for console replaying. [#32116](https://github.com/facebook/react/pull/32116)
|
||||
* Updated the server component wire format to remove IDs for hints and console.log because they have no return value [#31671](https://github.com/facebook/react/pull/31671)
|
||||
* Exposed `registerServerReference` in client builds to handle server references in different environments. [#32534](https://github.com/facebook/react/pull/32534)
|
||||
* Added react-server-dom-parcel package which integrates Server Components with the [Parcel bundler](https://parceljs.org/) [#31725](https://github.com/facebook/react/pull/31725), [#32132](https://github.com/facebook/react/pull/32132), [#31799](https://github.com/facebook/react/pull/31799), [#32294](https://github.com/facebook/react/pull/32294), [#31741](https://github.com/facebook/react/pull/31741)
|
||||
|
||||
## 19.0.0 (December 5, 2024)
|
||||
|
||||
Below is a list of all new features, APIs, deprecations, and breaking changes. Read [React 19 release post](https://react.dev/blog/2024/04/25/react-19) and [React 19 upgrade guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) for more information.
|
||||
|
||||
22
MAINTAINERS
22
MAINTAINERS
@@ -1,22 +0,0 @@
|
||||
acdlite
|
||||
eps1lon
|
||||
gaearon
|
||||
gnoff
|
||||
unstubbable
|
||||
hoxyq
|
||||
jackpope
|
||||
jbonta
|
||||
jbrown215
|
||||
josephsavona
|
||||
kassens
|
||||
mattcarrollcode
|
||||
mofeiZ
|
||||
mvitousek
|
||||
pieterv
|
||||
poteto
|
||||
rickhanlonii
|
||||
sebmarkbage
|
||||
sethwebster
|
||||
sophiebits
|
||||
elicwhite
|
||||
yuzhi
|
||||
@@ -18,7 +18,7 @@
|
||||
//
|
||||
// 0.0.0-experimental-241c4467e-20200129
|
||||
|
||||
const ReactVersion = '19.2.0';
|
||||
const ReactVersion = '19.1.0';
|
||||
|
||||
// The label used by the @canary channel. Represents the upcoming release's
|
||||
// stability. Most of the time, this will be "canary", but we may temporarily
|
||||
@@ -33,7 +33,7 @@ const canaryChannelLabel = 'canary';
|
||||
const rcNumber = 0;
|
||||
|
||||
const stablePackages = {
|
||||
'eslint-plugin-react-hooks': '6.1.0',
|
||||
'eslint-plugin-react-hooks': '5.2.0',
|
||||
'jest-react': '0.17.0',
|
||||
react: ReactVersion,
|
||||
'react-art': ReactVersion,
|
||||
@@ -42,12 +42,12 @@ const stablePackages = {
|
||||
'react-server-dom-turbopack': ReactVersion,
|
||||
'react-server-dom-parcel': ReactVersion,
|
||||
'react-is': ReactVersion,
|
||||
'react-reconciler': '0.33.0',
|
||||
'react-refresh': '0.18.0',
|
||||
'react-reconciler': '0.32.0',
|
||||
'react-refresh': '0.17.0',
|
||||
'react-test-renderer': ReactVersion,
|
||||
'use-subscription': '1.12.0',
|
||||
'use-sync-external-store': '1.6.0',
|
||||
scheduler: '0.27.0',
|
||||
'use-subscription': '1.11.0',
|
||||
'use-sync-external-store': '1.5.0',
|
||||
scheduler: '0.26.0',
|
||||
};
|
||||
|
||||
// These packages do not exist in the @canary or @latest channel, only
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
'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,
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* 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,8 +21,4 @@ dist
|
||||
.spr.yml
|
||||
testfilter.txt
|
||||
|
||||
bundle-oss.sh
|
||||
|
||||
# forgive
|
||||
*.vsix
|
||||
.vscode-test
|
||||
bundle-oss.sh
|
||||
@@ -1,59 +0,0 @@
|
||||
## 19.1.0-rc.1 (April 21, 2025)
|
||||
|
||||
## eslint-plugin-react-hooks
|
||||
* Temporarily disable ref access in render validation [#32839](https://github.com/facebook/react/pull/32839) by [@poteto](https://github.com/poteto)
|
||||
* Fix type error with recommended config [#32666](https://github.com/facebook/react/pull/32666) by [@niklasholm](https://github.com/niklasholm)
|
||||
* Merge rule from eslint-plugin-react-compiler into `react-hooks` plugin [#32416](https://github.com/facebook/react/pull/32416) by [@michaelfaith](https://github.com/michaelfaith)
|
||||
* Add dev dependencies for typescript migration [#32279](https://github.com/facebook/react/pull/32279) by [@michaelfaith](https://github.com/michaelfaith)
|
||||
* Support v9 context api [#32045](https://github.com/facebook/react/pull/32045) by [@michaelfaith](https://github.com/michaelfaith)
|
||||
* Support eslint 8+ flat plugin syntax out of the box for eslint-plugin-react-compiler [#32120](https://github.com/facebook/react/pull/32120) by [@orta](https://github.com/orta)
|
||||
|
||||
## babel-plugin-react-compiler
|
||||
* Support satisfies operator [#32742](https://github.com/facebook/react/pull/32742) by [@rodrigofariow](https://github.com/rodrigofariow)
|
||||
* Fix inferEffectDependencies lint false positives [#32769](https://github.com/facebook/react/pull/32769) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Fix hoisting of let declarations [#32724](https://github.com/facebook/react/pull/32724) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Avoid failing builds when import specifiers conflict or shadow vars [#32663](https://github.com/facebook/react/pull/32663) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Optimize components declared with arrow function and implicit return and `compilationMode: 'infer'` [#31792](https://github.com/facebook/react/pull/31792) by [@dimaMachina](https://github.com/dimaMachina)
|
||||
* Validate static components [#32683](https://github.com/facebook/react/pull/32683) by [@josephsavona](https://github.com/josephsavona)
|
||||
* Hoist dependencies from functions more conservatively [#32616](https://github.com/facebook/react/pull/32616) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Implement NumericLiteral as ObjectPropertyKey [#31791](https://github.com/facebook/react/pull/31791) by [@dimaMachina](https://github.com/dimaMachina)
|
||||
* Avoid bailouts when inserting gating [#32598](https://github.com/facebook/react/pull/32598) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Stop bailing out early for hoisted gated functions [#32597](https://github.com/facebook/react/pull/32597) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Add shape for Array.from [#32522](https://github.com/facebook/react/pull/32522) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Patch array and argument spread mutability [#32521](https://github.com/facebook/react/pull/32521) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Make CompilerError compatible with reflection [#32539](https://github.com/facebook/react/pull/32539) by [@poteto](https://github.com/poteto)
|
||||
* Add simple walltime measurement [#32331](https://github.com/facebook/react/pull/32331) by [@poteto](https://github.com/poteto)
|
||||
* Improve error messages for unhandled terminal and instruction kinds [#32324](https://github.com/facebook/react/pull/32324) by [@inottn](https://github.com/inottn)
|
||||
* Handle TSInstantiationExpression in lowerExpression [#32302](https://github.com/facebook/react/pull/32302) by [@inottn](https://github.com/inottn)
|
||||
* Fix invalid Array.map type [#32095](https://github.com/facebook/react/pull/32095) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Patch for JSX escape sequences in @babel/generator [#32131](https://github.com/facebook/react/pull/32131) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* `JSXText` emits incorrect with bracket [#32138](https://github.com/facebook/react/pull/32138) by [@himself65](https://github.com/himself65)
|
||||
* Validation against calling impure functions [#31960](https://github.com/facebook/react/pull/31960) by [@josephsavona](https://github.com/josephsavona)
|
||||
* Always target node [#32091](https://github.com/facebook/react/pull/32091) by [@poteto](https://github.com/poteto)
|
||||
* Patch compilationMode:infer object method edge case [#32055](https://github.com/facebook/react/pull/32055) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Generate ts defs [#31994](https://github.com/facebook/react/pull/31994) by [@poteto](https://github.com/poteto)
|
||||
* Relax react peer dep requirement [#31915](https://github.com/facebook/react/pull/31915) by [@poteto](https://github.com/poteto)
|
||||
* Allow type cast expressions with refs [#31871](https://github.com/facebook/react/pull/31871) by [@josephsavona](https://github.com/josephsavona)
|
||||
* Add shape for global Object.keys [#31583](https://github.com/facebook/react/pull/31583) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Optimize method calls w props receiver [#31775](https://github.com/facebook/react/pull/31775) by [@josephsavona](https://github.com/josephsavona)
|
||||
* Fix dropped ref with spread props in InlineJsxTransform [#31726](https://github.com/facebook/react/pull/31726) by [@jackpope](https://github.com/jackpope)
|
||||
* Support for non-declatation for in/of iterators [#31710](https://github.com/facebook/react/pull/31710) by [@mvitousek](https://github.com/mvitousek)
|
||||
* Support for context variable loop iterators [#31709](https://github.com/facebook/react/pull/31709) by [@mvitousek](https://github.com/mvitousek)
|
||||
* Replace deprecated dependency in `eslint-plugin-react-compiler` [#31629](https://github.com/facebook/react/pull/31629) by [@rakleed](https://github.com/rakleed)
|
||||
* Support enableRefAsProp in jsx transform [#31558](https://github.com/facebook/react/pull/31558) by [@jackpope](https://github.com/jackpope)
|
||||
* Fix: ref.current now correctly reactive [#31521](https://github.com/facebook/react/pull/31521) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Outline JSX with non-jsx children [#31442](https://github.com/facebook/react/pull/31442) by [@gsathya](https://github.com/gsathya)
|
||||
* Outline jsx with duplicate attributes [#31441](https://github.com/facebook/react/pull/31441) by [@gsathya](https://github.com/gsathya)
|
||||
* Store original and new prop names [#31440](https://github.com/facebook/react/pull/31440) by [@gsathya](https://github.com/gsathya)
|
||||
* Stabilize compiler output: sort deps and decls by name [#31362](https://github.com/facebook/react/pull/31362) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Bugfix for hoistable deps for nested functions [#31345](https://github.com/facebook/react/pull/31345) by [@mofeiZ](https://github.com/mofeiZ)
|
||||
* Remove compiler runtime-compat fixture library [#31430](https://github.com/facebook/react/pull/31430) by [@poteto](https://github.com/poteto)
|
||||
* Wrap inline jsx transform codegen in conditional [#31267](https://github.com/facebook/react/pull/31267) by [@jackpope](https://github.com/jackpope)
|
||||
* Check if local identifier is a hook when resolving globals [#31384](https://github.com/facebook/react/pull/31384) by [@poteto](https://github.com/poteto)
|
||||
* Handle member expr as computed property [#31344](https://github.com/facebook/react/pull/31344) by [@gsathya](https://github.com/gsathya)
|
||||
* Fix to ref access check to ban ref?.current [#31360](https://github.com/facebook/react/pull/31360) by [@mvitousek](https://github.com/mvitousek)
|
||||
* InlineJSXTransform transforms jsx inside function expressions [#31282](https://github.com/facebook/react/pull/31282) by [@josephsavona](https://github.com/josephsavona)
|
||||
|
||||
## Other
|
||||
* Add shebang to banner [#32225](https://github.com/facebook/react/pull/32225) by [@Jeremy-Hibiki](https://github.com/Jeremy-Hibiki)
|
||||
* remove terser from react-compiler-runtime build [#31326](https://github.com/facebook/react/pull/31326) by [@henryqdineen](https://github.com/henryqdineen)
|
||||
1217
compiler/Cargo.lock
generated
Normal file
1217
compiler/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
61
compiler/Cargo.toml
Normal file
61
compiler/Cargo.toml
Normal file
@@ -0,0 +1,61 @@
|
||||
[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,13 +9,6 @@ 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'});
|
||||
}
|
||||
@@ -112,7 +105,6 @@ 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',
|
||||
@@ -128,7 +120,6 @@ 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({
|
||||
@@ -152,7 +143,6 @@ 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());
|
||||
@@ -176,7 +166,6 @@ 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,9 +19,7 @@ import BabelPluginReactCompiler, {
|
||||
PluginOptions,
|
||||
CompilerPipelineValue,
|
||||
parsePluginOptions,
|
||||
printReactiveFunctionWithOutlined,
|
||||
printFunctionWithOutlined,
|
||||
} from 'babel-plugin-react-compiler';
|
||||
} from 'babel-plugin-react-compiler/src';
|
||||
import clsx from 'clsx';
|
||||
import invariant from 'invariant';
|
||||
import {useSnackbar} from 'notistack';
|
||||
@@ -43,6 +41,8 @@ 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';
|
||||
import {CompilerErrorDetail} from 'babel-plugin-react-compiler/src';
|
||||
import invariant from 'invariant';
|
||||
import type {editor} from 'monaco-editor';
|
||||
import * as monaco from 'monaco-editor';
|
||||
@@ -89,9 +89,6 @@ 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';
|
||||
import {type CompilerError} from 'babel-plugin-react-compiler/src';
|
||||
import parserBabel from 'prettier/plugins/babel';
|
||||
import * as prettierPluginEstree from 'prettier/plugins/estree';
|
||||
import * as prettier from 'prettier/standalone';
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
*/
|
||||
|
||||
import type {Dispatch, ReactNode} from 'react';
|
||||
import {useEffect, useReducer} from 'react';
|
||||
import {useReducer} from 'react';
|
||||
import createContext from '../lib/createContext';
|
||||
import {emptyStore} from '../lib/defaultStore';
|
||||
import {saveStore, type Store} from '../lib/stores';
|
||||
import type {Store} from '../lib/stores';
|
||||
import {saveStore} from '../lib/stores';
|
||||
|
||||
const StoreContext = createContext<Store>();
|
||||
|
||||
@@ -30,11 +31,6 @@ 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}>
|
||||
@@ -63,14 +59,19 @@ 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,7 +6,10 @@
|
||||
*/
|
||||
|
||||
import {Monaco} from '@monaco-editor/react';
|
||||
import {CompilerErrorDetail, ErrorSeverity} from 'babel-plugin-react-compiler';
|
||||
import {
|
||||
CompilerErrorDetail,
|
||||
ErrorSeverity,
|
||||
} from 'babel-plugin-react-compiler/src';
|
||||
import {MarkerSeverity, type editor} from 'monaco-editor';
|
||||
|
||||
function mapReactCompilerSeverityToMonaco(
|
||||
@@ -51,7 +54,7 @@ export function renderReactCompilerMarkers({
|
||||
model,
|
||||
details,
|
||||
}: ReactCompilerMarkerConfig): void {
|
||||
const markers: Array<editor.IMarkerData> = [];
|
||||
let markers = [];
|
||||
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/api-reference/config/typescript for more information.
|
||||
// see https://nextjs.org/docs/app/building-your-application/configuring/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 --dts\" \"yarn workspace react-compiler-runtime run build\"",
|
||||
"build:compiler": "cd ../.. && concurrently -n compiler,runtime \"yarn workspace babel-plugin-react-compiler run build\" \"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 --workers=4"
|
||||
"test": "playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.18.9",
|
||||
@@ -22,30 +22,30 @@
|
||||
"@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.26.0",
|
||||
"@babel/preset-typescript": "^7.18.9",
|
||||
"@babel/traverse": "^7.18.9",
|
||||
"@babel/types": "7.26.3",
|
||||
"@babel/types": "7.18.9",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@monaco-editor/react": "^4.4.6",
|
||||
"@playwright/test": "^1.51.1",
|
||||
"@playwright/test": "^1.42.1",
|
||||
"@use-gesture/react": "^10.2.22",
|
||||
"hermes-eslint": "^0.25.0",
|
||||
"hermes-parser": "^0.25.0",
|
||||
"invariant": "^2.2.4",
|
||||
"lz-string": "^1.5.0",
|
||||
"monaco-editor": "^0.52.0",
|
||||
"next": "^15.2.0-canary.64",
|
||||
"next": "^15.0.1",
|
||||
"notistack": "^3.0.0-alpha.7",
|
||||
"prettier": "^3.3.3",
|
||||
"pretty-format": "^29.3.1",
|
||||
"re-resizable": "^6.9.16",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
"react": "19.0.0-rc-77b637d6-20241016",
|
||||
"react-dom": "19.0.0-rc-77b637d6-20241016"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.11.9",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"clsx": "^1.2.1",
|
||||
"concurrently": "^7.4.0",
|
||||
@@ -55,5 +55,9 @@
|
||||
"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: 3,
|
||||
retries: 2,
|
||||
// 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,15 +23,6 @@
|
||||
"@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"
|
||||
@@ -68,17 +59,6 @@
|
||||
"@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"
|
||||
@@ -86,13 +66,6 @@
|
||||
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"
|
||||
@@ -104,26 +77,26 @@
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@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==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@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"
|
||||
"@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"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@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==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
"@babel/traverse" "^7.24.8"
|
||||
"@babel/types" "^7.24.8"
|
||||
|
||||
"@babel/helper-module-imports@^7.24.7":
|
||||
version "7.24.7"
|
||||
@@ -133,14 +106,6 @@
|
||||
"@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"
|
||||
@@ -151,40 +116,26 @@
|
||||
"@babel/helper-validator-identifier" "^7.24.7"
|
||||
"@babel/traverse" "^7.25.2"
|
||||
|
||||
"@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==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@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/types" "^7.24.7"
|
||||
|
||||
"@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-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==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@babel/helper-member-expression-to-functions" "^7.25.9"
|
||||
"@babel/helper-optimise-call-expression" "^7.25.9"
|
||||
"@babel/traverse" "^7.26.5"
|
||||
"@babel/helper-member-expression-to-functions" "^7.24.8"
|
||||
"@babel/helper-optimise-call-expression" "^7.24.7"
|
||||
"@babel/traverse" "^7.25.0"
|
||||
|
||||
"@babel/helper-simple-access@^7.24.7":
|
||||
version "7.24.7"
|
||||
@@ -194,39 +145,29 @@
|
||||
"@babel/traverse" "^7.24.7"
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@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==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.25.9"
|
||||
"@babel/types" "^7.25.9"
|
||||
"@babel/traverse" "^7.24.7"
|
||||
"@babel/types" "^7.24.7"
|
||||
|
||||
"@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-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-validator-identifier@^7.24.7":
|
||||
"@babel/helper-validator-identifier@^7.18.6", "@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"
|
||||
@@ -252,13 +193,6 @@
|
||||
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"
|
||||
@@ -266,27 +200,13 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^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":
|
||||
"@babel/plugin-syntax-typescript@^7.18.9", "@babel/plugin-syntax-typescript@^7.24.7":
|
||||
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"
|
||||
@@ -294,7 +214,7 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.24.8"
|
||||
|
||||
"@babel/plugin-transform-modules-commonjs@^7.18.9":
|
||||
"@babel/plugin-transform-modules-commonjs@^7.18.9", "@babel/plugin-transform-modules-commonjs@^7.24.7":
|
||||
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==
|
||||
@@ -303,14 +223,6 @@
|
||||
"@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"
|
||||
@@ -344,16 +256,16 @@
|
||||
"@babel/helper-annotate-as-pure" "^7.24.7"
|
||||
"@babel/helper-plugin-utils" "^7.24.7"
|
||||
|
||||
"@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==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@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/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/preset-react@^7.18.9":
|
||||
version "7.24.7"
|
||||
@@ -367,16 +279,16 @@
|
||||
"@babel/plugin-transform-react-jsx-development" "^7.24.7"
|
||||
"@babel/plugin-transform-react-pure-annotations" "^7.24.7"
|
||||
|
||||
"@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==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@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/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/runtime@^7.21.0":
|
||||
version "7.25.6"
|
||||
@@ -394,16 +306,7 @@
|
||||
"@babel/parser" "^7.25.0"
|
||||
"@babel/types" "^7.25.0"
|
||||
|
||||
"@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":
|
||||
"@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":
|
||||
version "7.25.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41"
|
||||
integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==
|
||||
@@ -416,34 +319,22 @@
|
||||
debug "^4.3.1"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@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==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@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/helper-validator-identifier" "^7.18.6"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@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==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@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"
|
||||
"@babel/helper-string-parser" "^7.24.8"
|
||||
"@babel/helper-validator-identifier" "^7.24.7"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@emnapi/runtime@^1.2.0":
|
||||
version "1.3.1"
|
||||
@@ -698,10 +589,10 @@
|
||||
dependencies:
|
||||
"@monaco-editor/loader" "^1.4.0"
|
||||
|
||||
"@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/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/eslint-plugin-next@15.0.1":
|
||||
version "15.0.1"
|
||||
@@ -710,45 +601,45 @@
|
||||
dependencies:
|
||||
fast-glob "3.3.1"
|
||||
|
||||
"@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-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-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-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-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-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-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-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-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-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-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-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-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-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-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==
|
||||
"@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==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
@@ -781,12 +672,12 @@
|
||||
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
||||
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
||||
|
||||
"@playwright/test@^1.51.1":
|
||||
version "1.51.1"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.51.1.tgz#75357d513221a7be0baad75f01e966baf9c41a2e"
|
||||
integrity sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q==
|
||||
"@playwright/test@^1.42.1":
|
||||
version "1.47.2"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.47.2.tgz#dbe7051336bfc5cc599954214f9111181dbc7475"
|
||||
integrity sha512-jTXRsoSPONAs8Za9QEQdyjFn+0ZQFjCiIztAIF6bi1HqhBzG9Ma7g1WotyiGqFSBRZjIEqMdT8RUlbk1QVhzCQ==
|
||||
dependencies:
|
||||
playwright "1.51.1"
|
||||
playwright "1.47.2"
|
||||
|
||||
"@rtsao/scc@^1.1.0":
|
||||
version "1.1.0"
|
||||
@@ -825,12 +716,12 @@
|
||||
resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
|
||||
integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
|
||||
|
||||
"@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==
|
||||
"@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==
|
||||
dependencies:
|
||||
tslib "^2.8.0"
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@types/json5@^0.0.29":
|
||||
version "0.0.29"
|
||||
@@ -842,15 +733,17 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4"
|
||||
integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==
|
||||
|
||||
"@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-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@^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==
|
||||
"@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==
|
||||
dependencies:
|
||||
csstype "^3.0.2"
|
||||
|
||||
@@ -1249,14 +1142,14 @@ camelcase-css@^2.0.1:
|
||||
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
|
||||
|
||||
caniuse-lite@^1.0.30001579:
|
||||
version "1.0.30001715"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz"
|
||||
integrity sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==
|
||||
version "1.0.30001669"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz#fda8f1d29a8bfdc42de0c170d7f34a9cf19ed7a3"
|
||||
integrity sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==
|
||||
|
||||
caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001663:
|
||||
version "1.0.30001715"
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz"
|
||||
integrity sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==
|
||||
version "1.0.30001664"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz#d588d75c9682d3301956b05a3749652a80677df4"
|
||||
integrity sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==
|
||||
|
||||
chalk@^2.4.2:
|
||||
version "2.4.2"
|
||||
@@ -2575,11 +2468,6 @@ 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"
|
||||
@@ -2794,27 +2682,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.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==
|
||||
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==
|
||||
dependencies:
|
||||
"@next/env" "15.2.0-canary.66"
|
||||
"@next/env" "15.0.1"
|
||||
"@swc/counter" "0.1.3"
|
||||
"@swc/helpers" "0.5.15"
|
||||
"@swc/helpers" "0.5.13"
|
||||
busboy "1.6.0"
|
||||
caniuse-lite "^1.0.30001579"
|
||||
postcss "8.4.31"
|
||||
styled-jsx "5.1.6"
|
||||
optionalDependencies:
|
||||
"@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"
|
||||
"@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"
|
||||
sharp "^0.33.5"
|
||||
|
||||
node-releases@^2.0.18:
|
||||
@@ -3008,17 +2896,17 @@ pirates@^4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
|
||||
integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==
|
||||
|
||||
playwright-core@1.51.1:
|
||||
version "1.51.1"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.51.1.tgz#d57f0393e02416f32a47cf82b27533656a8acce1"
|
||||
integrity sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw==
|
||||
playwright-core@1.47.2:
|
||||
version "1.47.2"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.47.2.tgz#7858da9377fa32a08be46ba47d7523dbd9460a4e"
|
||||
integrity sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==
|
||||
|
||||
playwright@1.51.1:
|
||||
version "1.51.1"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.51.1.tgz#ae1467ee318083968ad28d6990db59f47a55390f"
|
||||
integrity sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==
|
||||
playwright@1.47.2:
|
||||
version "1.47.2"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.47.2.tgz#155688aa06491ee21fb3e7555b748b525f86eb20"
|
||||
integrity sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==
|
||||
dependencies:
|
||||
playwright-core "1.51.1"
|
||||
playwright-core "1.47.2"
|
||||
optionalDependencies:
|
||||
fsevents "2.3.2"
|
||||
|
||||
@@ -3137,12 +3025,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:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57"
|
||||
integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==
|
||||
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==
|
||||
dependencies:
|
||||
scheduler "^0.25.0"
|
||||
scheduler "0.25.0-rc-77b637d6-20241016"
|
||||
|
||||
react-is@^16.13.1:
|
||||
version "16.13.1"
|
||||
@@ -3154,10 +3042,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:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
|
||||
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
|
||||
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==
|
||||
|
||||
read-cache@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -3279,10 +3167,10 @@ safe-regex-test@^1.0.3:
|
||||
es-errors "^1.3.0"
|
||||
is-regex "^1.1.4"
|
||||
|
||||
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==
|
||||
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==
|
||||
|
||||
semver@^6.3.1:
|
||||
version "6.3.1"
|
||||
@@ -3629,6 +3517,11 @@ 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"
|
||||
@@ -3666,11 +3559,6 @@ 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"
|
||||
|
||||
21
compiler/crates/react_build_hir/Cargo.toml
Normal file
21
compiler/crates/react_build_hir/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[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 }
|
||||
3
compiler/crates/react_build_hir/README.md
Normal file
3
compiler/crates/react_build_hir/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Build-HIR
|
||||
|
||||
This crate converts from `react_estree` into React Compiler's HIR format as the first phase of compilation.
|
||||
746
compiler/crates/react_build_hir/src/build.rs
Normal file
746
compiler/crates/react_build_hir/src/build.rs
Normal file
@@ -0,0 +1,746 @@
|
||||
/*
|
||||
* 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
322
compiler/crates/react_build_hir/src/builder.rs
Normal file
322
compiler/crates/react_build_hir/src/builder.rs
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* 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,
|
||||
))
|
||||
}
|
||||
}
|
||||
44
compiler/crates/react_build_hir/src/context.rs
Normal file
44
compiler/crates/react_build_hir/src/context.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
63
compiler/crates/react_build_hir/src/error.rs
Normal file
63
compiler/crates/react_build_hir/src/error.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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,
|
||||
}
|
||||
14
compiler/crates/react_build_hir/src/lib.rs
Normal file
14
compiler/crates/react_build_hir/src/lib.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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::*;
|
||||
23
compiler/crates/react_diagnostics/Cargo.toml
Normal file
23
compiler/crates/react_diagnostics/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
[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 }
|
||||
10
compiler/crates/react_diagnostics/README.md
Normal file
10
compiler/crates/react_diagnostics/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# 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.
|
||||
285
compiler/crates/react_diagnostics/src/diagnostic.rs
Normal file
285
compiler/crates/react_diagnostics/src/diagnostic.rs
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* 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(),
|
||||
)
|
||||
}
|
||||
19
compiler/crates/react_diagnostics/src/lib.rs
Normal file
19
compiler/crates/react_diagnostics/src/lib.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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()) }
|
||||
}
|
||||
22
compiler/crates/react_estree/Cargo.toml
Normal file
22
compiler/crates/react_estree/Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
||||
[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 }
|
||||
17
compiler/crates/react_estree/README.md
Normal file
17
compiler/crates/react_estree/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 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.
|
||||
31
compiler/crates/react_estree/build.rs
Normal file
31
compiler/crates/react_estree/build.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
30
compiler/crates/react_estree/src/binding.rs
Normal file
30
compiler/crates/react_estree/src/binding.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
528
compiler/crates/react_estree/src/fixtures/for-statement.json
Normal file
528
compiler/crates/react_estree/src/fixtures/for-statement.json
Normal file
@@ -0,0 +1,528 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
104
compiler/crates/react_estree/src/fixtures/import.json
Normal file
104
compiler/crates/react_estree/src/fixtures/import.json
Normal file
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
189
compiler/crates/react_estree/src/fixtures/simple.json
Normal file
189
compiler/crates/react_estree/src/fixtures/simple.json
Normal file
@@ -0,0 +1,189 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
351
compiler/crates/react_estree/src/fixtures/test.json
Normal file
351
compiler/crates/react_estree/src/fixtures/test.json
Normal file
@@ -0,0 +1,351 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
9031
compiler/crates/react_estree/src/generated.rs
Normal file
9031
compiler/crates/react_estree/src/generated.rs
Normal file
File diff suppressed because it is too large
Load Diff
149
compiler/crates/react_estree/src/generated_extensions.rs
Normal file
149
compiler/crates/react_estree/src/generated_extensions.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
295
compiler/crates/react_estree/src/js_value.rs
Normal file
295
compiler/crates/react_estree/src/js_value.rs
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
38
compiler/crates/react_estree/src/lib.rs
Normal file
38
compiler/crates/react_estree/src/lib.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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}"));
|
||||
});
|
||||
}
|
||||
}
|
||||
31
compiler/crates/react_estree/src/range.rs
Normal file
31
compiler/crates/react_estree/src/range.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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
@@ -0,0 +1,213 @@
|
||||
---
|
||||
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
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
---
|
||||
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
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,708 @@
|
||||
---
|
||||
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
@@ -0,0 +1,213 @@
|
||||
---
|
||||
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
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
---
|
||||
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
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,708 @@
|
||||
---
|
||||
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
|
||||
]
|
||||
}
|
||||
537
compiler/crates/react_estree/src/visit.rs
Normal file
537
compiler/crates/react_estree/src/visit.rs
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
* 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()")
|
||||
}
|
||||
}
|
||||
21
compiler/crates/react_estree_codegen/Cargo.toml
Normal file
21
compiler/crates/react_estree_codegen/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[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 }
|
||||
4
compiler/crates/react_estree_codegen/README.md
Normal file
4
compiler/crates/react_estree_codegen/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# 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.
|
||||
969
compiler/crates/react_estree_codegen/src/codegen.rs
Normal file
969
compiler/crates/react_estree_codegen/src/codegen.rs
Normal file
@@ -0,0 +1,969 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
1367
compiler/crates/react_estree_codegen/src/ecmascript.json
Normal file
1367
compiler/crates/react_estree_codegen/src/ecmascript.json
Normal file
File diff suppressed because it is too large
Load Diff
10
compiler/crates/react_estree_codegen/src/lib.rs
Normal file
10
compiler/crates/react_estree_codegen/src/lib.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* 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};
|
||||
24
compiler/crates/react_fixtures/Cargo.toml
Normal file
24
compiler/crates/react_fixtures/Cargo.toml
Normal file
@@ -0,0 +1,24 @@
|
||||
[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"] }
|
||||
3
compiler/crates/react_fixtures/README.md
Normal file
3
compiler/crates/react_fixtures/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# fixtures
|
||||
|
||||
This crate is for tests only, and runs the suite of compiler fixture tests.
|
||||
6
compiler/crates/react_fixtures/src/lib.rs
Normal file
6
compiler/crates/react_fixtures/src/lib.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
34
compiler/crates/react_fixtures/tests/fixtures/constant-propagation-constant-if-condition.js
vendored
Normal file
34
compiler/crates/react_fixtures/tests/fixtures/constant-propagation-constant-if-condition.js
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
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;
|
||||
}
|
||||
60
compiler/crates/react_fixtures/tests/fixtures/constant-propagation.js
vendored
Normal file
60
compiler/crates/react_fixtures/tests/fixtures/constant-propagation.js
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
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;
|
||||
}
|
||||
5
compiler/crates/react_fixtures/tests/fixtures/destructure-array.js
vendored
Normal file
5
compiler/crates/react_fixtures/tests/fixtures/destructure-array.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function Component(a, b) {
|
||||
const [c, , ...d] = a;
|
||||
const [[[e]], ...[f]] = b;
|
||||
return [c, d, e, f];
|
||||
}
|
||||
15
compiler/crates/react_fixtures/tests/fixtures/destructure-object.js
vendored
Normal file
15
compiler/crates/react_fixtures/tests/fixtures/destructure-object.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
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];
|
||||
}
|
||||
3
compiler/crates/react_fixtures/tests/fixtures/error.assign-to-global.js
vendored
Normal file
3
compiler/crates/react_fixtures/tests/fixtures/error.assign-to-global.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
function foo() {
|
||||
x = true;
|
||||
}
|
||||
7
compiler/crates/react_fixtures/tests/fixtures/for-statement.js
vendored
Normal file
7
compiler/crates/react_fixtures/tests/fixtures/for-statement.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
function foo() {
|
||||
let x = 0;
|
||||
for (let i = 0; i < 10; i = i + 1) {
|
||||
x = x + i;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
21
compiler/crates/react_fixtures/tests/fixtures/function-expressions.js
vendored
Normal file
21
compiler/crates/react_fixtures/tests/fixtures/function-expressions.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
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;
|
||||
};
|
||||
}
|
||||
16
compiler/crates/react_fixtures/tests/fixtures/identifiers.js
vendored
Normal file
16
compiler/crates/react_fixtures/tests/fixtures/identifiers.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user