From 71d0896a4a1b31e14baeb7e427fc4724dbe972ff Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 20:49:25 -0400 Subject: [PATCH 1/9] [forgive] Log inferEffectDependencies (#32996) This was missed earlier. Co-authored-by: Jordan Brown --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32996). * #33002 * #33001 * #33000 * #32999 * #32998 * #32997 * __->__ #32996 Co-authored-by: Jordan Brown --- .../babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index 61f57f68cfeb9..8dfdc76978cc2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -392,6 +392,11 @@ function runWithEnvironment( if (env.config.inferEffectDependencies) { inferEffectDependencies(hir); + log({ + kind: 'hir', + name: 'InferEffectDependencies', + value: hir, + }); } if (env.config.inlineJsxTransform) { From cd7d236682ff3ba4996a5e1568f148bd6ac91862 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 20:51:38 -0400 Subject: [PATCH 2/9] [forgive] Emit AutoDepsDecoration event when inferring effect deps (#32997) Emits a new event for decorating inferred effect dependencies. Co-authored-by: Jordan Brown --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32997). * #33002 * #33001 * #33000 * #32999 * #32998 * __->__ #32997 * #32996 --------- Co-authored-by: Jordan Brown --- .../src/Entrypoint/Options.ts | 8 +++- .../src/Inference/InferEffectDependencies.ts | 40 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts index e0c670c5641cd..db55673fa133a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts @@ -182,7 +182,8 @@ export type LoggerEvent = | CompileDiagnosticEvent | CompileSkipEvent | PipelineErrorEvent - | TimingEvent; + | TimingEvent + | AutoDepsDecorations; export type CompileErrorEvent = { kind: 'CompileError'; @@ -219,6 +220,11 @@ export type TimingEvent = { kind: 'Timing'; measurement: PerformanceMeasure; }; +export type AutoDepsDecorations = { + kind: 'AutoDepsDecorations'; + useEffectCallExpr: t.SourceLocation | null; + decorations: Array; +}; export type Logger = { logEvent: (filename: string | null, event: LoggerEvent) => void; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts index 0d27ac7ca0f69..e14b1af11598b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts @@ -188,6 +188,7 @@ export function inferEffectDependencies(fn: HIRFunction): void { * the `infer-effect-deps/pruned-nonreactive-obj` fixture for an * explanation. */ + const usedDeps = []; for (const dep of scopeInfo.deps) { if ( ((isUseRefType(dep.identifier) || @@ -207,8 +208,19 @@ export function inferEffectDependencies(fn: HIRFunction): void { ); newInstructions.push(...instructions); effectDeps.push(place); + usedDeps.push(dep); } + // For LSP autodeps feature. + fn.env.logger?.logEvent(fn.env.filename, { + kind: 'AutoDepsDecorations', + useEffectCallExpr: + typeof value.loc !== 'symbol' ? value.loc : null, + decorations: collectDepUsages(usedDeps, fnExpr.value).map(loc => + typeof loc !== 'symbol' ? loc : null, + ), + }); + newInstructions.push({ id: makeInstructionId(0), loc: GeneratedSource, @@ -340,3 +352,31 @@ function inferReactiveIdentifiers(fn: HIRFunction): Set { } return reactiveIds; } + +function collectDepUsages( + deps: Array, + fnExpr: FunctionExpression, +): Array { + const identifiers: Map = new Map(); + const loadedDeps: Set = new Set(); + const sourceLocations = []; + for (const dep of deps) { + identifiers.set(dep.identifier.id, dep); + } + + for (const [, block] of fnExpr.loweredFunc.func.body.blocks) { + for (const instr of block.instructions) { + if (instr.value.kind === 'LoadLocal') { + loadedDeps.add(instr.lvalue.identifier.id); + } + for (const place of eachInstructionOperand(instr)) { + if (loadedDeps.has(place.identifier.id)) { + // TODO(@jbrown215): handle member exprs!! + sourceLocations.push(place.identifier.loc); + } + } + } + } + + return sourceLocations; +} From e25e8c7575350a1dd217f56e7dcf530f14a90080 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 21:21:44 -0400 Subject: [PATCH 3/9] [forgive] Hacky first pass at adding decorations for inferred deps (#32998) Draws basic decorations for inferred deps on hover. Co-authored-by: Jordan Brown --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32998). * #33002 * #33001 * #33000 * #32999 * __->__ #32998 Co-authored-by: Jordan Brown --- .../src/Entrypoint/Options.ts | 4 +- .../src/Inference/InferEffectDependencies.ts | 30 +++++++--- .../react-forgive/client/src/extension.ts | 42 +++++++++++--- .../custom-requests/autodepsdecorations.ts | 18 ++++++ .../react-forgive/server/src/index.ts | 58 ++++++++++++++++++- .../server/src/utils/lsp-adapter.ts | 11 ++++ 6 files changed, 145 insertions(+), 18 deletions(-) create mode 100644 compiler/packages/react-forgive/server/src/custom-requests/autodepsdecorations.ts create mode 100644 compiler/packages/react-forgive/server/src/utils/lsp-adapter.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts index db55673fa133a..25f67deb974f1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts @@ -222,8 +222,8 @@ export type TimingEvent = { }; export type AutoDepsDecorations = { kind: 'AutoDepsDecorations'; - useEffectCallExpr: t.SourceLocation | null; - decorations: Array; + useEffectCallExpr: t.SourceLocation; + decorations: Array; }; export type Logger = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts index e14b1af11598b..7eb17bcbcb4ef 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts @@ -1,3 +1,11 @@ +/** + * 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. + */ + +import * as t from '@babel/types'; import {CompilerError, SourceLocation} from '..'; import { ArrayExpression, @@ -212,14 +220,20 @@ export function inferEffectDependencies(fn: HIRFunction): void { } // For LSP autodeps feature. - fn.env.logger?.logEvent(fn.env.filename, { - kind: 'AutoDepsDecorations', - useEffectCallExpr: - typeof value.loc !== 'symbol' ? value.loc : null, - decorations: collectDepUsages(usedDeps, fnExpr.value).map(loc => - typeof loc !== 'symbol' ? loc : null, - ), - }); + const decorations: Array = []; + for (const loc of collectDepUsages(usedDeps, fnExpr.value)) { + if (typeof loc === 'symbol') { + continue; + } + decorations.push(loc); + } + if (typeof value.loc !== 'symbol') { + fn.env.logger?.logEvent(fn.env.filename, { + kind: 'AutoDepsDecorations', + useEffectCallExpr: value.loc, + decorations, + }); + } newInstructions.push({ id: makeInstructionId(0), diff --git a/compiler/packages/react-forgive/client/src/extension.ts b/compiler/packages/react-forgive/client/src/extension.ts index 402f298fd74c5..0a7ae394354de 100644 --- a/compiler/packages/react-forgive/client/src/extension.ts +++ b/compiler/packages/react-forgive/client/src/extension.ts @@ -1,17 +1,22 @@ import * as path from 'path'; -import {ExtensionContext, window as Window} from 'vscode'; +import * as vscode from 'vscode'; import { LanguageClient, LanguageClientOptions, + Position, ServerOptions, TransportKind, } from 'vscode-languageclient/node'; let client: LanguageClient; -export function activate(context: ExtensionContext) { +export function activate(context: vscode.ExtensionContext) { const serverModule = context.asAbsolutePath(path.join('dist', 'server.js')); + const documentSelector = [ + {scheme: 'file', language: 'javascriptreact'}, + {scheme: 'file', language: 'typescriptreact'}, + ]; // If the extension is launched in debug mode then the debug server options are used // Otherwise the run options are used @@ -27,10 +32,7 @@ export function activate(context: ExtensionContext) { }; const clientOptions: LanguageClientOptions = { - documentSelector: [ - {scheme: 'file', language: 'javascriptreact'}, - {scheme: 'file', language: 'typescriptreact'}, - ], + documentSelector, progressOnInitialization: true, }; @@ -43,12 +45,38 @@ export function activate(context: ExtensionContext) { clientOptions, ); } catch { - Window.showErrorMessage( + vscode.window.showErrorMessage( `React Analyzer couldn't be started. See the output channel for details.`, ); return; } + vscode.languages.registerHoverProvider(documentSelector, { + provideHover(_document, position, _token) { + client + .sendRequest('react/autodepsdecorations', position) + .then((decorations: Array<[Position, Position]>) => { + for (const [start, end] of decorations) { + const range = new vscode.Range( + new vscode.Position(start.line, start.character), + new vscode.Position(end.line, end.character), + ); + const vscodeDecoration = + vscode.window.createTextEditorDecorationType({ + backgroundColor: 'red', + }); + vscode.window.activeTextEditor?.setDecorations(vscodeDecoration, [ + { + range, + hoverMessage: 'hehe', + }, + ]); + } + }); + return null; + }, + }); + client.registerProposedFeatures(); client.start(); } diff --git a/compiler/packages/react-forgive/server/src/custom-requests/autodepsdecorations.ts b/compiler/packages/react-forgive/server/src/custom-requests/autodepsdecorations.ts new file mode 100644 index 0000000000000..e05bac5c0fd5a --- /dev/null +++ b/compiler/packages/react-forgive/server/src/custom-requests/autodepsdecorations.ts @@ -0,0 +1,18 @@ +import {AutoDepsDecorations} from 'babel-plugin-react-compiler/src/Entrypoint'; +import {Position} from 'vscode-languageserver-textdocument'; +import {sourceLocationToRange} from '../utils/lsp-adapter'; + +export type Range = [Position, Position]; +export type AutoDepsDecorationsLSPEvent = { + useEffectCallExpr: Range; + decorations: Array; +}; + +export function mapCompilerEventToLSPEvent( + event: AutoDepsDecorations, +): AutoDepsDecorationsLSPEvent { + return { + useEffectCallExpr: sourceLocationToRange(event.useEffectCallExpr), + decorations: event.decorations.map(sourceLocationToRange), + }; +} diff --git a/compiler/packages/react-forgive/server/src/index.ts b/compiler/packages/react-forgive/server/src/index.ts index 395969c5e06bf..c4b4f72c295ad 100644 --- a/compiler/packages/react-forgive/server/src/index.ts +++ b/compiler/packages/react-forgive/server/src/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {TextDocument} from 'vscode-languageserver-textdocument'; +import {Position, TextDocument} from 'vscode-languageserver-textdocument'; import { CodeLens, createConnection, @@ -24,6 +24,10 @@ import { LoggerEvent, } from 'babel-plugin-react-compiler/src/Entrypoint/Options'; import {babelLocationToRange, getRangeFirstCharacter} from './compiler/compat'; +import { + AutoDepsDecorationsLSPEvent, + mapCompilerEventToLSPEvent, +} from './custom-requests/autodepsdecorations'; const SUPPORTED_LANGUAGE_IDS = new Set([ 'javascript', @@ -37,17 +41,48 @@ const documents = new TextDocuments(TextDocument); let compilerOptions: PluginOptions | null = null; let compiledFns: Set = new Set(); +let autoDepsDecorations: Array = []; connection.onInitialize((_params: InitializeParams) => { // TODO(@poteto) get config fr compilerOptions = resolveReactConfig('.') ?? defaultOptions; compilerOptions = { ...compilerOptions, + environment: { + ...compilerOptions.environment, + inferEffectDependencies: [ + { + function: { + importSpecifierName: 'useEffect', + source: 'react', + }, + numRequiredArgs: 1, + }, + { + function: { + importSpecifierName: 'useSpecialEffect', + source: 'shared-runtime', + }, + numRequiredArgs: 2, + }, + { + function: { + importSpecifierName: 'default', + source: 'useEffectWrapper', + }, + numRequiredArgs: 1, + }, + ], + }, logger: { logEvent(_filename: string | null, event: LoggerEvent) { + connection.console.info(`Received event: ${event.kind}`); if (event.kind === 'CompileSuccess') { compiledFns.add(event); } + if (event.kind === 'AutoDepsDecorations') { + autoDepsDecorations.push(mapCompilerEventToLSPEvent(event)); + } }, }, }; @@ -67,6 +102,7 @@ connection.onInitialized(() => { documents.onDidChangeContent(async event => { connection.console.info(`Changed: ${event.document.uri}`); compiledFns.clear(); + autoDepsDecorations = []; if (SUPPORTED_LANGUAGE_IDS.has(event.document.languageId)) { const text = event.document.getText(); await compile({ @@ -79,6 +115,7 @@ documents.onDidChangeContent(async event => { connection.onDidChangeWatchedFiles(change => { compiledFns.clear(); + autoDepsDecorations = []; connection.console.log( change.changes.map(c => `File changed: ${c.uri}`).join('\n'), ); @@ -118,6 +155,25 @@ connection.onCodeLensResolve(lens => { return lens; }); +connection.onRequest('react/autodepsdecorations', (position: Position) => { + connection.console.log('Client hovering on: ' + JSON.stringify(position)); + connection.console.log(JSON.stringify(autoDepsDecorations, null, 2)); + + for (const dec of autoDepsDecorations) { + // TODO: extract to helper + if ( + position.line >= dec.useEffectCallExpr[0].line && + position.line <= dec.useEffectCallExpr[1].line + ) { + connection.console.log( + 'found decoration: ' + JSON.stringify(dec.decorations), + ); + return dec.decorations; + } + } + return null; +}); + documents.listen(connection); connection.listen(); connection.console.info(`React Analyzer running in node ${process.version}`); diff --git a/compiler/packages/react-forgive/server/src/utils/lsp-adapter.ts b/compiler/packages/react-forgive/server/src/utils/lsp-adapter.ts new file mode 100644 index 0000000000000..3a6b92320995b --- /dev/null +++ b/compiler/packages/react-forgive/server/src/utils/lsp-adapter.ts @@ -0,0 +1,11 @@ +import * as t from '@babel/types'; +import {Position} from 'vscode-languageserver/node'; + +export function sourceLocationToRange( + loc: t.SourceLocation, +): [Position, Position] { + return [ + {line: loc.start.line - 1, character: loc.start.column}, + {line: loc.end.line - 1, character: loc.end.column}, + ]; +} From 7b21c464890ec991d95c88b5d68802a6c8b3bd8e Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 21:27:22 -0400 Subject: [PATCH 4/9] [forgive] Refactor inferred deps (#32999) Refactor. Co-authored-by: Jordan Brown --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32999). * #33002 * #33001 * #33000 * __->__ #32999 Co-authored-by: Jordan Brown --- .../src/Entrypoint/Options.ts | 4 +- .../src/Inference/InferEffectDependencies.ts | 5 +- .../react-forgive/client/src/colors.ts | 73 +++++++++++++++++++ .../react-forgive/client/src/extension.ts | 60 ++++++++++----- .../custom-requests/autodepsdecorations.ts | 18 ----- .../react-forgive/server/src/index.ts | 28 +++---- .../src/requests/autodepsdecorations.ts | 28 +++++++ .../server/src/utils/lsp-adapter.ts | 11 --- .../react-forgive/server/src/utils/range.ts | 19 +++++ compiler/packages/react-forgive/tsconfig.json | 16 ++++ 10 files changed, 196 insertions(+), 66 deletions(-) create mode 100644 compiler/packages/react-forgive/client/src/colors.ts delete mode 100644 compiler/packages/react-forgive/server/src/custom-requests/autodepsdecorations.ts create mode 100644 compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts delete mode 100644 compiler/packages/react-forgive/server/src/utils/lsp-adapter.ts create mode 100644 compiler/packages/react-forgive/server/src/utils/range.ts create mode 100644 compiler/packages/react-forgive/tsconfig.json diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts index 25f67deb974f1..5ede6fec5ce58 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts @@ -183,7 +183,7 @@ export type LoggerEvent = | CompileSkipEvent | PipelineErrorEvent | TimingEvent - | AutoDepsDecorations; + | AutoDepsDecorationsEvent; export type CompileErrorEvent = { kind: 'CompileError'; @@ -220,7 +220,7 @@ export type TimingEvent = { kind: 'Timing'; measurement: PerformanceMeasure; }; -export type AutoDepsDecorations = { +export type AutoDepsDecorationsEvent = { kind: 'AutoDepsDecorations'; useEffectCallExpr: t.SourceLocation; decorations: Array; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts index 7eb17bcbcb4ef..275a1a91b154c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts @@ -380,7 +380,10 @@ function collectDepUsages( for (const [, block] of fnExpr.loweredFunc.func.body.blocks) { for (const instr of block.instructions) { - if (instr.value.kind === 'LoadLocal') { + if ( + instr.value.kind === 'LoadLocal' && + identifiers.has(instr.value.place.identifier.id) + ) { loadedDeps.add(instr.lvalue.identifier.id); } for (const place of eachInstructionOperand(instr)) { diff --git a/compiler/packages/react-forgive/client/src/colors.ts b/compiler/packages/react-forgive/client/src/colors.ts new file mode 100644 index 0000000000000..5d98b078085cd --- /dev/null +++ b/compiler/packages/react-forgive/client/src/colors.ts @@ -0,0 +1,73 @@ +type RGB = [number, number, number]; + +const int = Math.floor; + +export class Color { + constructor( + private r: number, + private g: number, + private b: number, + ) {} + + toAlphaString(a: number) { + return this.toCssString(a); + } + toString() { + return this.toCssString(1); + } + + /** + * Adjust the color by a multiplier to lighten (`> 1.0`) or darken (`< 1.0`) the color. Returns a new + * instance. + */ + adjusted(mult: number) { + const adjusted = Color.redistribute([ + this.r * mult, + this.g * mult, + this.b * mult, + ]); + return new Color(...adjusted); + } + + private toCssString(a: number) { + return `rgba(${this.r},${this.g},${this.b},${a})`; + } + /** + * Redistributes rgb, maintaing hue until its clamped. + * https://stackoverflow.com/a/141943 + */ + private static redistribute([r, g, b]: RGB): RGB { + const threshold = 255.999; + const max = Math.max(r, g, b); + if (max <= threshold) { + return [int(r), int(g), int(b)]; + } + const total = r + g + b; + if (total >= 3 * threshold) { + return [int(threshold), int(threshold), int(threshold)]; + } + const x = (3 * threshold - total) / (3 * max - total); + const gray = threshold - x * max; + return [int(gray + x * r), int(gray + x * g), int(gray + x * b)]; + } +} + +export const BLACK = new Color(0, 0, 0); +export const WHITE = new Color(255, 255, 255); + +const COLOR_POOL = [ + new Color(249, 65, 68), + new Color(243, 114, 44), + new Color(248, 150, 30), + new Color(249, 132, 74), + new Color(249, 199, 79), + new Color(144, 190, 109), + new Color(67, 170, 139), + new Color(77, 144, 142), + new Color(87, 117, 144), + new Color(39, 125, 161), +]; + +export function getColorFor(index: number): Color { + return COLOR_POOL[Math.abs(index) % COLOR_POOL.length]!; +} diff --git a/compiler/packages/react-forgive/client/src/extension.ts b/compiler/packages/react-forgive/client/src/extension.ts index 0a7ae394354de..01da3fa49131f 100644 --- a/compiler/packages/react-forgive/client/src/extension.ts +++ b/compiler/packages/react-forgive/client/src/extension.ts @@ -4,12 +4,30 @@ import * as vscode from 'vscode'; import { LanguageClient, LanguageClientOptions, - Position, + type Position, + RequestType, ServerOptions, TransportKind, } from 'vscode-languageclient/node'; +import {WHITE} from './colors'; let client: LanguageClient; +const inferredEffectDepDecoration = + vscode.window.createTextEditorDecorationType({ + backgroundColor: WHITE.toAlphaString(0.3), + }); + +type Range = [Position, Position]; +interface AutoDepsDecorationsParams { + position: Position; +} +namespace AutoDepsDecorationsRequest { + export const type = new RequestType< + AutoDepsDecorationsParams, + Array | null, + void + >('react/autodeps_decorations'); +} export function activate(context: vscode.ExtensionContext) { const serverModule = context.asAbsolutePath(path.join('dist', 'server.js')); @@ -54,23 +72,24 @@ export function activate(context: vscode.ExtensionContext) { vscode.languages.registerHoverProvider(documentSelector, { provideHover(_document, position, _token) { client - .sendRequest('react/autodepsdecorations', position) - .then((decorations: Array<[Position, Position]>) => { - for (const [start, end] of decorations) { - const range = new vscode.Range( - new vscode.Position(start.line, start.character), - new vscode.Position(end.line, end.character), + .sendRequest(AutoDepsDecorationsRequest.type, {position}) + .then(decorations => { + if (Array.isArray(decorations)) { + const decorationOptions = decorations.map(([start, end]) => { + return { + range: new vscode.Range( + new vscode.Position(start.line, start.character), + new vscode.Position(end.line, end.character), + ), + hoverMessage: 'Inferred as an effect dependency', + }; + }); + vscode.window.activeTextEditor?.setDecorations( + inferredEffectDepDecoration, + decorationOptions, ); - const vscodeDecoration = - vscode.window.createTextEditorDecorationType({ - backgroundColor: 'red', - }); - vscode.window.activeTextEditor?.setDecorations(vscodeDecoration, [ - { - range, - hoverMessage: 'hehe', - }, - ]); + } else { + clearDecorations(inferredEffectDepDecoration); } }); return null; @@ -85,4 +104,11 @@ export function deactivate(): Thenable | undefined { if (client !== undefined) { return client.stop(); } + return; +} + +export function clearDecorations( + decorationType: vscode.TextEditorDecorationType, +) { + vscode.window.activeTextEditor?.setDecorations(decorationType, []); } diff --git a/compiler/packages/react-forgive/server/src/custom-requests/autodepsdecorations.ts b/compiler/packages/react-forgive/server/src/custom-requests/autodepsdecorations.ts deleted file mode 100644 index e05bac5c0fd5a..0000000000000 --- a/compiler/packages/react-forgive/server/src/custom-requests/autodepsdecorations.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {AutoDepsDecorations} from 'babel-plugin-react-compiler/src/Entrypoint'; -import {Position} from 'vscode-languageserver-textdocument'; -import {sourceLocationToRange} from '../utils/lsp-adapter'; - -export type Range = [Position, Position]; -export type AutoDepsDecorationsLSPEvent = { - useEffectCallExpr: Range; - decorations: Array; -}; - -export function mapCompilerEventToLSPEvent( - event: AutoDepsDecorations, -): AutoDepsDecorationsLSPEvent { - return { - useEffectCallExpr: sourceLocationToRange(event.useEffectCallExpr), - decorations: event.decorations.map(sourceLocationToRange), - }; -} diff --git a/compiler/packages/react-forgive/server/src/index.ts b/compiler/packages/react-forgive/server/src/index.ts index c4b4f72c295ad..6432e3efc6aea 100644 --- a/compiler/packages/react-forgive/server/src/index.ts +++ b/compiler/packages/react-forgive/server/src/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {Position, TextDocument} from 'vscode-languageserver-textdocument'; +import {TextDocument} from 'vscode-languageserver-textdocument'; import { CodeLens, createConnection, @@ -19,15 +19,17 @@ import {compile, lastResult} from './compiler'; import {type PluginOptions} from 'babel-plugin-react-compiler/src'; import {resolveReactConfig} from './compiler/options'; import { - CompileSuccessEvent, + type CompileSuccessEvent, + type LoggerEvent, defaultOptions, - LoggerEvent, } from 'babel-plugin-react-compiler/src/Entrypoint/Options'; import {babelLocationToRange, getRangeFirstCharacter} from './compiler/compat'; import { - AutoDepsDecorationsLSPEvent, + type AutoDepsDecorationsLSPEvent, + AutoDepsDecorationsRequest, mapCompilerEventToLSPEvent, -} from './custom-requests/autodepsdecorations'; +} from './requests/autodepsdecorations'; +import {isPositionWithinRange} from './utils/range'; const SUPPORTED_LANGUAGE_IDS = new Set([ 'javascript', @@ -155,19 +157,11 @@ connection.onCodeLensResolve(lens => { return lens; }); -connection.onRequest('react/autodepsdecorations', (position: Position) => { - connection.console.log('Client hovering on: ' + JSON.stringify(position)); - connection.console.log(JSON.stringify(autoDepsDecorations, null, 2)); - +connection.onRequest(AutoDepsDecorationsRequest.type, async params => { + const position = params.position; + connection.console.debug('Client hovering on: ' + JSON.stringify(position)); for (const dec of autoDepsDecorations) { - // TODO: extract to helper - if ( - position.line >= dec.useEffectCallExpr[0].line && - position.line <= dec.useEffectCallExpr[1].line - ) { - connection.console.log( - 'found decoration: ' + JSON.stringify(dec.decorations), - ); + if (isPositionWithinRange(position, dec.useEffectCallExpr)) { return dec.decorations; } } diff --git a/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts new file mode 100644 index 0000000000000..43f4ac1fb9a2b --- /dev/null +++ b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts @@ -0,0 +1,28 @@ +import {type AutoDepsDecorationsEvent} from 'babel-plugin-react-compiler/src/Entrypoint'; +import {type Position} from 'vscode-languageserver-textdocument'; +import {RequestType} from 'vscode-languageserver/node'; +import {type Range, sourceLocationToRange} from '../utils/range'; + +export type AutoDepsDecorationsLSPEvent = { + useEffectCallExpr: Range; + decorations: Array; +}; +export interface AutoDepsDecorationsParams { + position: Position; +} +export namespace AutoDepsDecorationsRequest { + export const type = new RequestType< + AutoDepsDecorationsParams, + Array | null, + void + >('react/autodeps_decorations'); +} + +export function mapCompilerEventToLSPEvent( + event: AutoDepsDecorationsEvent, +): AutoDepsDecorationsLSPEvent { + return { + useEffectCallExpr: sourceLocationToRange(event.useEffectCallExpr), + decorations: event.decorations.map(sourceLocationToRange), + }; +} diff --git a/compiler/packages/react-forgive/server/src/utils/lsp-adapter.ts b/compiler/packages/react-forgive/server/src/utils/lsp-adapter.ts deleted file mode 100644 index 3a6b92320995b..0000000000000 --- a/compiler/packages/react-forgive/server/src/utils/lsp-adapter.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as t from '@babel/types'; -import {Position} from 'vscode-languageserver/node'; - -export function sourceLocationToRange( - loc: t.SourceLocation, -): [Position, Position] { - return [ - {line: loc.start.line - 1, character: loc.start.column}, - {line: loc.end.line - 1, character: loc.end.column}, - ]; -} diff --git a/compiler/packages/react-forgive/server/src/utils/range.ts b/compiler/packages/react-forgive/server/src/utils/range.ts new file mode 100644 index 0000000000000..e0665ba8fe8c2 --- /dev/null +++ b/compiler/packages/react-forgive/server/src/utils/range.ts @@ -0,0 +1,19 @@ +import * as t from '@babel/types'; +import {type Position} from 'vscode-languageserver/node'; + +export type Range = [Position, Position]; +export function isPositionWithinRange( + position: Position, + [start, end]: Range, +): boolean { + return position.line >= start.line && position.line <= end.line; +} + +export function sourceLocationToRange( + loc: t.SourceLocation, +): [Position, Position] { + return [ + {line: loc.start.line - 1, character: loc.start.column}, + {line: loc.end.line - 1, character: loc.end.column}, + ]; +} diff --git a/compiler/packages/react-forgive/tsconfig.json b/compiler/packages/react-forgive/tsconfig.json new file mode 100644 index 0000000000000..6aeffaeb354da --- /dev/null +++ b/compiler/packages/react-forgive/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "@tsconfig/strictest/tsconfig.json", + "compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16", + "rootDir": "../", + "noEmit": true, + "jsx": "react-jsxdev", + "lib": ["ES2022"], + + "target": "ES2022", + "importsNotUsedAsValues": "remove", + }, + "exclude": ["node_modules"], + "include": ["server/src/**/*.ts", "client/src/**/*.ts"], +} From f765082996f056c2abb354eb43cec3a3bf535264 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 21:31:57 -0400 Subject: [PATCH 5/9] [forgive] Add code action to remove dependency array (#33000) Adds a new codeaction event in the compiler and handler in forgive. This allows you to remove a dependency array when you're editing a range that is within an autodep eligible function. Co-authored-by: Jordan Brown --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33000). * #33002 * #33001 * __->__ #33000 Co-authored-by: Jordan Brown --- .../src/Entrypoint/Options.ts | 10 ++- .../src/Inference/InferEffectDependencies.ts | 26 +++++- .../react-forgive/server/src/index.ts | 80 +++++++++++++++++-- .../src/requests/autodepsdecorations.ts | 2 +- .../react-forgive/server/src/utils/range.ts | 16 ++++ 5 files changed, 125 insertions(+), 9 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts index 5ede6fec5ce58..0adbf3077c285 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts @@ -183,7 +183,8 @@ export type LoggerEvent = | CompileSkipEvent | PipelineErrorEvent | TimingEvent - | AutoDepsDecorationsEvent; + | AutoDepsDecorationsEvent + | AutoDepsEligibleEvent; export type CompileErrorEvent = { kind: 'CompileError'; @@ -222,9 +223,14 @@ export type TimingEvent = { }; export type AutoDepsDecorationsEvent = { kind: 'AutoDepsDecorations'; - useEffectCallExpr: t.SourceLocation; + fnLoc: t.SourceLocation; decorations: Array; }; +export type AutoDepsEligibleEvent = { + kind: 'AutoDepsEligible'; + fnLoc: t.SourceLocation; + depArrayLoc: t.SourceLocation; +}; export type Logger = { logEvent: (filename: string | null, event: LoggerEvent) => void; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts index 275a1a91b154c..472e4cfae3cdc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts @@ -230,7 +230,7 @@ export function inferEffectDependencies(fn: HIRFunction): void { if (typeof value.loc !== 'symbol') { fn.env.logger?.logEvent(fn.env.filename, { kind: 'AutoDepsDecorations', - useEffectCallExpr: value.loc, + fnLoc: value.loc, decorations, }); } @@ -258,6 +258,30 @@ export function inferEffectDependencies(fn: HIRFunction): void { rewriteInstrs.set(instr.id, newInstructions); fn.env.inferredEffectLocations.add(callee.loc); } + } else if ( + value.args.length >= 2 && + value.args.length - 1 === autodepFnLoads.get(callee.identifier.id) && + value.args[0].kind === 'Identifier' + ) { + const penultimateArg = value.args[value.args.length - 2]; + const depArrayArg = value.args[value.args.length - 1]; + if ( + depArrayArg.kind !== 'Spread' && + penultimateArg.kind !== 'Spread' && + typeof depArrayArg.loc !== 'symbol' && + typeof penultimateArg.loc !== 'symbol' && + typeof value.loc !== 'symbol' + ) { + fn.env.logger?.logEvent(fn.env.filename, { + kind: 'AutoDepsEligible', + fnLoc: value.loc, + depArrayLoc: { + ...depArrayArg.loc, + start: penultimateArg.loc.end, + end: depArrayArg.loc.end, + }, + }); + } } } } diff --git a/compiler/packages/react-forgive/server/src/index.ts b/compiler/packages/react-forgive/server/src/index.ts index 6432e3efc6aea..e4b75df19442a 100644 --- a/compiler/packages/react-forgive/server/src/index.ts +++ b/compiler/packages/react-forgive/server/src/index.ts @@ -7,10 +7,13 @@ import {TextDocument} from 'vscode-languageserver-textdocument'; import { + CodeAction, + CodeActionKind, CodeLens, createConnection, type InitializeParams, type InitializeResult, + Position, ProposedFeatures, TextDocuments, TextDocumentSyncKind, @@ -29,7 +32,12 @@ import { AutoDepsDecorationsRequest, mapCompilerEventToLSPEvent, } from './requests/autodepsdecorations'; -import {isPositionWithinRange} from './utils/range'; +import { + isPositionWithinRange, + isRangeWithinRange, + Range, + sourceLocationToRange, +} from './utils/range'; const SUPPORTED_LANGUAGE_IDS = new Set([ 'javascript', @@ -44,6 +52,15 @@ const documents = new TextDocuments(TextDocument); let compilerOptions: PluginOptions | null = null; let compiledFns: Set = new Set(); let autoDepsDecorations: Array = []; +let codeActionEvents: Array = []; + +type CodeActionLSPEvent = { + title: string; + kind: CodeActionKind; + newText: string; + anchorRange: Range; + editRange: {start: Position; end: Position}; +}; connection.onInitialize((_params: InitializeParams) => { // TODO(@poteto) get config fr @@ -85,6 +102,16 @@ connection.onInitialize((_params: InitializeParams) => { if (event.kind === 'AutoDepsDecorations') { autoDepsDecorations.push(mapCompilerEventToLSPEvent(event)); } + if (event.kind === 'AutoDepsEligible') { + const depArrayLoc = sourceLocationToRange(event.depArrayLoc); + codeActionEvents.push({ + title: 'Use React Compiler inferred dependency array', + kind: CodeActionKind.QuickFix, + newText: '', + anchorRange: sourceLocationToRange(event.fnLoc), + editRange: {start: depArrayLoc[0], end: depArrayLoc[1]}, + }); + } }, }, }; @@ -92,6 +119,7 @@ connection.onInitialize((_params: InitializeParams) => { capabilities: { textDocumentSync: TextDocumentSyncKind.Full, codeLensProvider: {resolveProvider: true}, + codeActionProvider: {resolveProvider: true}, }, }; return result; @@ -103,8 +131,7 @@ connection.onInitialized(() => { documents.onDidChangeContent(async event => { connection.console.info(`Changed: ${event.document.uri}`); - compiledFns.clear(); - autoDepsDecorations = []; + resetState(); if (SUPPORTED_LANGUAGE_IDS.has(event.document.languageId)) { const text = event.document.getText(); await compile({ @@ -116,8 +143,7 @@ documents.onDidChangeContent(async event => { }); connection.onDidChangeWatchedFiles(change => { - compiledFns.clear(); - autoDepsDecorations = []; + resetState(); connection.console.log( change.changes.map(c => `File changed: ${c.uri}`).join('\n'), ); @@ -157,6 +183,44 @@ connection.onCodeLensResolve(lens => { return lens; }); +connection.onCodeAction(params => { + connection.console.log('onCodeAction'); + connection.console.log(JSON.stringify(params, null, 2)); + const codeActions: Array = []; + for (const codeActionEvent of codeActionEvents) { + if ( + isRangeWithinRange( + [params.range.start, params.range.end], + codeActionEvent.anchorRange, + ) + ) { + codeActions.push( + CodeAction.create( + codeActionEvent.title, + { + changes: { + [params.textDocument.uri]: [ + { + newText: codeActionEvent.newText, + range: codeActionEvent.editRange, + }, + ], + }, + }, + codeActionEvent.kind, + ), + ); + } + } + return codeActions; +}); + +connection.onCodeActionResolve(codeAction => { + connection.console.log('onCodeActionResolve'); + connection.console.log(JSON.stringify(codeAction, null, 2)); + return codeAction; +}); + connection.onRequest(AutoDepsDecorationsRequest.type, async params => { const position = params.position; connection.console.debug('Client hovering on: ' + JSON.stringify(position)); @@ -168,6 +232,12 @@ connection.onRequest(AutoDepsDecorationsRequest.type, async params => { return null; }); +function resetState() { + compiledFns.clear(); + autoDepsDecorations = []; + codeActionEvents = []; +} + documents.listen(connection); connection.listen(); connection.console.info(`React Analyzer running in node ${process.version}`); diff --git a/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts index 43f4ac1fb9a2b..6f3a4051fb941 100644 --- a/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts +++ b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts @@ -22,7 +22,7 @@ export function mapCompilerEventToLSPEvent( event: AutoDepsDecorationsEvent, ): AutoDepsDecorationsLSPEvent { return { - useEffectCallExpr: sourceLocationToRange(event.useEffectCallExpr), + useEffectCallExpr: sourceLocationToRange(event.fnLoc), decorations: event.decorations.map(sourceLocationToRange), }; } diff --git a/compiler/packages/react-forgive/server/src/utils/range.ts b/compiler/packages/react-forgive/server/src/utils/range.ts index e0665ba8fe8c2..8a16f1bc096a4 100644 --- a/compiler/packages/react-forgive/server/src/utils/range.ts +++ b/compiler/packages/react-forgive/server/src/utils/range.ts @@ -2,6 +2,7 @@ import * as t from '@babel/types'; import {type Position} from 'vscode-languageserver/node'; export type Range = [Position, Position]; + export function isPositionWithinRange( position: Position, [start, end]: Range, @@ -9,6 +10,21 @@ export function isPositionWithinRange( return position.line >= start.line && position.line <= end.line; } +export function isRangeWithinRange(aRange: Range, bRange: Range): boolean { + const startComparison = comparePositions(aRange[0], bRange[0]); + const endComparison = comparePositions(aRange[1], bRange[1]); + return startComparison >= 0 && endComparison <= 0; +} + +function comparePositions(a: Position, b: Position): number { + const lineComparison = a.line - b.line; + if (lineComparison === 0) { + return a.character - b.character; + } else { + return lineComparison; + } +} + export function sourceLocationToRange( loc: t.SourceLocation, ): [Position, Position] { From b75af0467099b7fd0e668b500adb0888b7b21d10 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 21:32:11 -0400 Subject: [PATCH 6/9] [forgive] Don't crash if we couldn't compile (#33001) Compiler shouldn't crash Forgive if it can't compile (eg parse error due to being mid-typing). Co-authored-by: Jordan Brown --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33001). * #33002 * __->__ #33001 * #33000 --------- Co-authored-by: Jordan Brown --- .../packages/react-forgive/server/src/index.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/compiler/packages/react-forgive/server/src/index.ts b/compiler/packages/react-forgive/server/src/index.ts index e4b75df19442a..edb6d63f02507 100644 --- a/compiler/packages/react-forgive/server/src/index.ts +++ b/compiler/packages/react-forgive/server/src/index.ts @@ -134,11 +134,17 @@ documents.onDidChangeContent(async event => { resetState(); if (SUPPORTED_LANGUAGE_IDS.has(event.document.languageId)) { const text = event.document.getText(); - await compile({ - text, - file: event.document.uri, - options: compilerOptions, - }); + try { + await compile({ + text, + file: event.document.uri, + options: compilerOptions, + }); + } catch (err) { + if (err instanceof Error) { + connection.console.error(err.stack ?? ''); + } + } } }); From 3a5335676f7df4318e8e399f8f69e880db724f78 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 21:55:15 -0400 Subject: [PATCH 7/9] [forgive] Polish decorations (#33002) Polishes up decorations. Co-authored-by: Jordan Brown --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33002). * #33004 * #33003 * __->__ #33002 Co-authored-by: Jordan Brown --- .../src/Inference/InferEffectDependencies.ts | 1 + .../react-forgive/client/src/autodeps.ts | 99 +++++++++++++++++++ .../react-forgive/client/src/extension.ts | 71 +++++-------- .../react-forgive/client/src/mapping.ts | 15 +++ .../react-forgive/server/src/index.ts | 53 +++++----- .../src/requests/autodepsdecorations.ts | 2 +- 6 files changed, 170 insertions(+), 71 deletions(-) create mode 100644 compiler/packages/react-forgive/client/src/autodeps.ts create mode 100644 compiler/packages/react-forgive/client/src/mapping.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts index 472e4cfae3cdc..a70f49dacd13a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts @@ -261,6 +261,7 @@ export function inferEffectDependencies(fn: HIRFunction): void { } else if ( value.args.length >= 2 && value.args.length - 1 === autodepFnLoads.get(callee.identifier.id) && + value.args[0] != null && value.args[0].kind === 'Identifier' ) { const penultimateArg = value.args[value.args.length - 2]; diff --git a/compiler/packages/react-forgive/client/src/autodeps.ts b/compiler/packages/react-forgive/client/src/autodeps.ts new file mode 100644 index 0000000000000..62cfc92a47390 --- /dev/null +++ b/compiler/packages/react-forgive/client/src/autodeps.ts @@ -0,0 +1,99 @@ +import * as vscode from 'vscode'; +import { + LanguageClient, + RequestType, + type Position, +} from 'vscode-languageclient/node'; +import {positionLiteralToVSCodePosition, positionsToRange} from './mapping'; + +export type AutoDepsDecorationsLSPEvent = { + useEffectCallExpr: [Position, Position]; + decorations: Array<[Position, Position]>; +}; + +export interface AutoDepsDecorationsParams { + position: Position; +} + +export namespace AutoDepsDecorationsRequest { + export const type = new RequestType< + AutoDepsDecorationsParams, + AutoDepsDecorationsLSPEvent | null, + void + >('react/autodeps_decorations'); +} + +const inferredEffectDepDecoration = + vscode.window.createTextEditorDecorationType({ + // TODO: make configurable? + borderColor: new vscode.ThemeColor('diffEditor.move.border'), + borderStyle: 'solid', + borderWidth: '0 0 4px 0', + }); + +let currentlyDecoratedAutoDepFnLoc: vscode.Range | null = null; +export function getCurrentlyDecoratedAutoDepFnLoc(): vscode.Range | null { + return currentlyDecoratedAutoDepFnLoc; +} +export function setCurrentlyDecoratedAutoDepFnLoc(range: vscode.Range): void { + currentlyDecoratedAutoDepFnLoc = range; +} +export function clearCurrentlyDecoratedAutoDepFnLoc(): void { + currentlyDecoratedAutoDepFnLoc = null; +} + +let decorationRequestId = 0; +export type AutoDepsDecorationsOptions = { + shouldUpdateCurrent: boolean; +}; +export function requestAutoDepsDecorations( + client: LanguageClient, + position: vscode.Position, + options: AutoDepsDecorationsOptions, +) { + const id = ++decorationRequestId; + client + .sendRequest(AutoDepsDecorationsRequest.type, {position}) + .then(response => { + if (response !== null) { + const { + decorations, + useEffectCallExpr: [start, end], + } = response; + // Maintain ordering + if (decorationRequestId === id) { + if (options.shouldUpdateCurrent) { + setCurrentlyDecoratedAutoDepFnLoc(positionsToRange(start, end)); + } + drawInferredEffectDepDecorations(decorations); + } + } else { + clearCurrentlyDecoratedAutoDepFnLoc(); + clearDecorations(inferredEffectDepDecoration); + } + }); +} + +export function drawInferredEffectDepDecorations( + decorations: Array<[Position, Position]>, +): void { + const decorationOptions = decorations.map(([start, end]) => { + return { + range: new vscode.Range( + positionLiteralToVSCodePosition(start), + positionLiteralToVSCodePosition(end), + ), + hoverMessage: 'Inferred as an effect dependency', + }; + }); + vscode.window.activeTextEditor?.setDecorations( + inferredEffectDepDecoration, + decorationOptions, + ); +} + +export function clearDecorations( + decorationType: vscode.TextEditorDecorationType, +) { + vscode.window.activeTextEditor?.setDecorations(decorationType, []); +} diff --git a/compiler/packages/react-forgive/client/src/extension.ts b/compiler/packages/react-forgive/client/src/extension.ts index 01da3fa49131f..74ad5414836df 100644 --- a/compiler/packages/react-forgive/client/src/extension.ts +++ b/compiler/packages/react-forgive/client/src/extension.ts @@ -5,29 +5,16 @@ import { LanguageClient, LanguageClientOptions, type Position, - RequestType, ServerOptions, TransportKind, } from 'vscode-languageclient/node'; -import {WHITE} from './colors'; +import {positionLiteralToVSCodePosition} from './mapping'; +import { + getCurrentlyDecoratedAutoDepFnLoc, + requestAutoDepsDecorations, +} from './autodeps'; let client: LanguageClient; -const inferredEffectDepDecoration = - vscode.window.createTextEditorDecorationType({ - backgroundColor: WHITE.toAlphaString(0.3), - }); - -type Range = [Position, Position]; -interface AutoDepsDecorationsParams { - position: Position; -} -namespace AutoDepsDecorationsRequest { - export const type = new RequestType< - AutoDepsDecorationsParams, - Array | null, - void - >('react/autodeps_decorations'); -} export function activate(context: vscode.ExtensionContext) { const serverModule = context.asAbsolutePath(path.join('dist', 'server.js')); @@ -71,31 +58,31 @@ export function activate(context: vscode.ExtensionContext) { vscode.languages.registerHoverProvider(documentSelector, { provideHover(_document, position, _token) { - client - .sendRequest(AutoDepsDecorationsRequest.type, {position}) - .then(decorations => { - if (Array.isArray(decorations)) { - const decorationOptions = decorations.map(([start, end]) => { - return { - range: new vscode.Range( - new vscode.Position(start.line, start.character), - new vscode.Position(end.line, end.character), - ), - hoverMessage: 'Inferred as an effect dependency', - }; - }); - vscode.window.activeTextEditor?.setDecorations( - inferredEffectDepDecoration, - decorationOptions, - ); - } else { - clearDecorations(inferredEffectDepDecoration); - } - }); + requestAutoDepsDecorations(client, position, {shouldUpdateCurrent: true}); return null; }, }); + vscode.workspace.onDidChangeTextDocument(async _e => { + const currentlyDecoratedAutoDepFnLoc = getCurrentlyDecoratedAutoDepFnLoc(); + if (currentlyDecoratedAutoDepFnLoc !== null) { + requestAutoDepsDecorations(client, currentlyDecoratedAutoDepFnLoc.start, { + shouldUpdateCurrent: false, + }); + } + }); + + vscode.commands.registerCommand( + 'react.requestAutoDepsDecorations', + (position: Position) => { + requestAutoDepsDecorations( + client, + positionLiteralToVSCodePosition(position), + {shouldUpdateCurrent: true}, + ); + }, + ); + client.registerProposedFeatures(); client.start(); } @@ -106,9 +93,3 @@ export function deactivate(): Thenable | undefined { } return; } - -export function clearDecorations( - decorationType: vscode.TextEditorDecorationType, -) { - vscode.window.activeTextEditor?.setDecorations(decorationType, []); -} diff --git a/compiler/packages/react-forgive/client/src/mapping.ts b/compiler/packages/react-forgive/client/src/mapping.ts new file mode 100644 index 0000000000000..0505011711795 --- /dev/null +++ b/compiler/packages/react-forgive/client/src/mapping.ts @@ -0,0 +1,15 @@ +import * as vscode from 'vscode'; +import {Position} from 'vscode-languageclient/node'; + +export function positionLiteralToVSCodePosition( + position: Position, +): vscode.Position { + return new vscode.Position(position.line, position.character); +} + +export function positionsToRange(start: Position, end: Position): vscode.Range { + return new vscode.Range( + positionLiteralToVSCodePosition(start), + positionLiteralToVSCodePosition(end), + ); +} diff --git a/compiler/packages/react-forgive/server/src/index.ts b/compiler/packages/react-forgive/server/src/index.ts index edb6d63f02507..0b43e9fcd2945 100644 --- a/compiler/packages/react-forgive/server/src/index.ts +++ b/compiler/packages/react-forgive/server/src/index.ts @@ -10,6 +10,7 @@ import { CodeAction, CodeActionKind, CodeLens, + Command, createConnection, type InitializeParams, type InitializeResult, @@ -96,6 +97,7 @@ connection.onInitialize((_params: InitializeParams) => { logger: { logEvent(_filename: string | null, event: LoggerEvent) { connection.console.info(`Received event: ${event.kind}`); + connection.console.debug(JSON.stringify(event, null, 2)); if (event.kind === 'CompileSuccess') { compiledFns.add(event); } @@ -191,7 +193,6 @@ connection.onCodeLensResolve(lens => { connection.onCodeAction(params => { connection.console.log('onCodeAction'); - connection.console.log(JSON.stringify(params, null, 2)); const codeActions: Array = []; for (const codeActionEvent of codeActionEvents) { if ( @@ -200,39 +201,41 @@ connection.onCodeAction(params => { codeActionEvent.anchorRange, ) ) { - codeActions.push( - CodeAction.create( - codeActionEvent.title, - { - changes: { - [params.textDocument.uri]: [ - { - newText: codeActionEvent.newText, - range: codeActionEvent.editRange, - }, - ], - }, + const codeAction = CodeAction.create( + codeActionEvent.title, + { + changes: { + [params.textDocument.uri]: [ + { + newText: codeActionEvent.newText, + range: codeActionEvent.editRange, + }, + ], }, - codeActionEvent.kind, - ), + }, + codeActionEvent.kind, ); + // After executing a codeaction, we want to draw autodep decorations again + codeAction.command = Command.create( + 'Request autodeps decorations', + 'react.requestAutoDepsDecorations', + codeActionEvent.anchorRange[0], + ); + codeActions.push(codeAction); } } return codeActions; }); -connection.onCodeActionResolve(codeAction => { - connection.console.log('onCodeActionResolve'); - connection.console.log(JSON.stringify(codeAction, null, 2)); - return codeAction; -}); - +/** + * The client can request the server to compute autodeps decorations based on a currently selected + * position if the selected position is within an autodep eligible function call. + */ connection.onRequest(AutoDepsDecorationsRequest.type, async params => { const position = params.position; - connection.console.debug('Client hovering on: ' + JSON.stringify(position)); - for (const dec of autoDepsDecorations) { - if (isPositionWithinRange(position, dec.useEffectCallExpr)) { - return dec.decorations; + for (const decoration of autoDepsDecorations) { + if (isPositionWithinRange(position, decoration.useEffectCallExpr)) { + return decoration; } } return null; diff --git a/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts index 6f3a4051fb941..1738bbcd8c502 100644 --- a/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts +++ b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts @@ -13,7 +13,7 @@ export interface AutoDepsDecorationsParams { export namespace AutoDepsDecorationsRequest { export const type = new RequestType< AutoDepsDecorationsParams, - Array | null, + AutoDepsDecorationsLSPEvent, void >('react/autodeps_decorations'); } From 8b9629c8106b55965ac6e4f078110b484b358101 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 21:55:24 -0400 Subject: [PATCH 8/9] [compiler] Fix copyright script (#33003) Don't try to open directories --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33003). * #33004 * __->__ #33003 * #33002 --------- Co-authored-by: Jordan Brown --- compiler/scripts/copyright.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/scripts/copyright.js b/compiler/scripts/copyright.js index da3c39fe859af..0a5ef2e29ae30 100644 --- a/compiler/scripts/copyright.js +++ b/compiler/scripts/copyright.js @@ -51,6 +51,9 @@ if (hasErrors) { } function processFile(file) { + if (fs.lstatSync(file).isDirectory()) { + return; + } let source = fs.readFileSync(file, 'utf8'); if (source.indexOf(META_COPYRIGHT_COMMENT_BLOCK) === 0) { From ad09027c161f1ce5d9b07bfcfb4ee4fb92444655 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Apr 2025 22:04:44 -0400 Subject: [PATCH 9/9] [compiler] Add missing copyrights (#33004) `yarn copyright` --- .../src/Entrypoint/Reanimated.ts | 7 +++++++ .../src/Entrypoint/ValidateNoUntransformedReferences.ts | 7 +++++++ .../src/HIR/AssertValidBlockNesting.ts | 7 +++++++ .../src/HIR/BuildReactiveScopeTerminalsHIR.ts | 7 +++++++ .../src/HIR/CollectHoistablePropertyLoads.ts | 7 +++++++ .../src/HIR/CollectOptionalChainDependencies.ts | 7 +++++++ .../src/HIR/MergeOverlappingReactiveScopesHIR.ts | 7 +++++++ .../src/HIR/PropagateScopeDependenciesHIR.ts | 7 +++++++ .../src/HIR/PruneUnusedLabelsHIR.ts | 7 +++++++ .../src/ReactiveScopes/StabilizeBlockIds.ts | 7 +++++++ .../babel-plugin-react-compiler/src/Transform/index.ts | 1 + .../src/Validation/ValidateNoCapitalizedCalls.ts | 1 + .../packages/babel-plugin-react-compiler/tsup.config.ts | 7 +++++++ .../packages/eslint-plugin-react-compiler/tsup.config.ts | 7 +++++++ compiler/packages/make-read-only-util/tsup.config.ts | 7 +++++++ compiler/packages/react-compiler-healthcheck/src/config.ts | 7 +++++++ .../packages/react-compiler-healthcheck/tsup.config.ts | 7 +++++++ compiler/packages/react-compiler-runtime/tsup.config.ts | 7 +++++++ compiler/packages/react-forgive/client/src/autodeps.ts | 7 +++++++ compiler/packages/react-forgive/client/src/colors.ts | 7 +++++++ compiler/packages/react-forgive/client/src/extension.ts | 7 +++++++ compiler/packages/react-forgive/client/src/mapping.ts | 7 +++++++ .../packages/react-forgive/server/src/compiler/compat.ts | 7 +++++++ .../server/src/requests/autodepsdecorations.ts | 7 +++++++ compiler/packages/react-forgive/server/src/utils/range.ts | 7 +++++++ compiler/packages/react-mcp-server/src/types/algolia.ts | 7 +++++++ compiler/packages/react-mcp-server/tsup.config.ts | 7 +++++++ compiler/scripts/release/prompt-for-otp.js | 6 ++++++ compiler/scripts/release/publish.js | 6 ++++++ compiler/scripts/release/shared/build-packages.js | 7 +++++++ compiler/scripts/release/shared/packages.js | 7 +++++++ compiler/scripts/release/shared/utils.js | 7 +++++++ 32 files changed, 210 insertions(+) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Reanimated.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Reanimated.ts index e946d7aab88c0..4f8a3e709d1c1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Reanimated.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Reanimated.ts @@ -1,3 +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. + */ + import type * as BabelCore from '@babel/core'; import {hasOwnProperty} from '../Utils/utils'; import {PluginOptions} from './Options'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts index a221b0485c3dc..5f6c6986e04fd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts @@ -1,3 +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. + */ + import {NodePath} from '@babel/core'; import * as t from '@babel/types'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting.ts index cd2024e1e1069..adfb0510582cd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidBlockNesting.ts @@ -1,3 +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. + */ + import {CompilerError} from '..'; import { BlockId, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts index 7c1fb54ea8058..6f69af4b4f2cd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts @@ -1,3 +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. + */ + import {CompilerError} from '../CompilerError'; import {getScopes, recursivelyTraverseItems} from './AssertValidBlockNesting'; import {Environment} from './Environment'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index cb6854d1b3674..e29ef51ce0806 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -1,3 +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. + */ + import {CompilerError} from '../CompilerError'; import {inRange} from '../ReactiveScopes/InferReactiveScopeVariables'; import {printDependency} from '../ReactiveScopes/PrintReactiveFunction'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts index 02a28b9f35776..cb787d04d0623 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts @@ -1,3 +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. + */ + import {CompilerError} from '..'; import {assertNonNull} from './CollectHoistablePropertyLoads'; import { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeOverlappingReactiveScopesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeOverlappingReactiveScopesHIR.ts index 5b286e917d0d3..96d20ea644265 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeOverlappingReactiveScopesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeOverlappingReactiveScopesHIR.ts @@ -1,3 +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. + */ + import { HIRFunction, InstructionId, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts index e12d10b40612b..934fd98f73daf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts @@ -1,3 +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. + */ + import { ScopeId, HIRFunction, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR.ts index bf10e9f1f36dd..f0c488c3e1ec7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PruneUnusedLabelsHIR.ts @@ -1,3 +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. + */ + import {CompilerError} from '..'; import {BlockId, GotoVariant, HIRFunction} from './HIR'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/StabilizeBlockIds.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/StabilizeBlockIds.ts index 26d83f9906443..9ad181547469a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/StabilizeBlockIds.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/StabilizeBlockIds.ts @@ -1,3 +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. + */ + import { BlockId, ReactiveFunction, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Transform/index.ts b/compiler/packages/babel-plugin-react-compiler/src/Transform/index.ts index 8665ead0b1af0..4f142104f210b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Transform/index.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Transform/index.ts @@ -4,4 +4,5 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ + export {transformFire} from './TransformFire'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts index 4ba70b64a8c94..8989cb1ac2d62 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ + import {CompilerError, EnvironmentConfig, ErrorSeverity} from '..'; import {HIRFunction, IdentifierId} from '../HIR'; import {DEFAULT_GLOBALS} from '../HIR/Globals'; diff --git a/compiler/packages/babel-plugin-react-compiler/tsup.config.ts b/compiler/packages/babel-plugin-react-compiler/tsup.config.ts index 12c04ec8a2480..dde9525256db6 100644 --- a/compiler/packages/babel-plugin-react-compiler/tsup.config.ts +++ b/compiler/packages/babel-plugin-react-compiler/tsup.config.ts @@ -1,3 +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. + */ + import {defineConfig} from 'tsup'; export default defineConfig({ diff --git a/compiler/packages/eslint-plugin-react-compiler/tsup.config.ts b/compiler/packages/eslint-plugin-react-compiler/tsup.config.ts index ac13d33bba5b3..3e3b1b13131a5 100644 --- a/compiler/packages/eslint-plugin-react-compiler/tsup.config.ts +++ b/compiler/packages/eslint-plugin-react-compiler/tsup.config.ts @@ -1,3 +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. + */ + import {defineConfig} from 'tsup'; export default defineConfig({ diff --git a/compiler/packages/make-read-only-util/tsup.config.ts b/compiler/packages/make-read-only-util/tsup.config.ts index cb65a61aaa319..ffef80abba260 100644 --- a/compiler/packages/make-read-only-util/tsup.config.ts +++ b/compiler/packages/make-read-only-util/tsup.config.ts @@ -1,3 +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. + */ + import {defineConfig} from 'tsup'; export default defineConfig({ diff --git a/compiler/packages/react-compiler-healthcheck/src/config.ts b/compiler/packages/react-compiler-healthcheck/src/config.ts index 9655d2654b8b9..f279bc5d22062 100644 --- a/compiler/packages/react-compiler-healthcheck/src/config.ts +++ b/compiler/packages/react-compiler-healthcheck/src/config.ts @@ -1,3 +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. + */ + export const config = { knownIncompatibleLibraries: [ 'mobx-react', diff --git a/compiler/packages/react-compiler-healthcheck/tsup.config.ts b/compiler/packages/react-compiler-healthcheck/tsup.config.ts index 9fe1e493dbf18..7addc79bf909a 100644 --- a/compiler/packages/react-compiler-healthcheck/tsup.config.ts +++ b/compiler/packages/react-compiler-healthcheck/tsup.config.ts @@ -1,3 +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. + */ + import {defineConfig} from 'tsup'; export default defineConfig({ diff --git a/compiler/packages/react-compiler-runtime/tsup.config.ts b/compiler/packages/react-compiler-runtime/tsup.config.ts index ebc8df6f14e67..30a7f9da96f0d 100644 --- a/compiler/packages/react-compiler-runtime/tsup.config.ts +++ b/compiler/packages/react-compiler-runtime/tsup.config.ts @@ -1,3 +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. + */ + import {defineConfig} from 'tsup'; export default defineConfig({ diff --git a/compiler/packages/react-forgive/client/src/autodeps.ts b/compiler/packages/react-forgive/client/src/autodeps.ts index 62cfc92a47390..ed41b34dcb7d8 100644 --- a/compiler/packages/react-forgive/client/src/autodeps.ts +++ b/compiler/packages/react-forgive/client/src/autodeps.ts @@ -1,3 +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. + */ + import * as vscode from 'vscode'; import { LanguageClient, diff --git a/compiler/packages/react-forgive/client/src/colors.ts b/compiler/packages/react-forgive/client/src/colors.ts index 5d98b078085cd..8989aa1c62ce9 100644 --- a/compiler/packages/react-forgive/client/src/colors.ts +++ b/compiler/packages/react-forgive/client/src/colors.ts @@ -1,3 +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. + */ + type RGB = [number, number, number]; const int = Math.floor; diff --git a/compiler/packages/react-forgive/client/src/extension.ts b/compiler/packages/react-forgive/client/src/extension.ts index 74ad5414836df..e9938c388a03c 100644 --- a/compiler/packages/react-forgive/client/src/extension.ts +++ b/compiler/packages/react-forgive/client/src/extension.ts @@ -1,3 +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. + */ + import * as path from 'path'; import * as vscode from 'vscode'; diff --git a/compiler/packages/react-forgive/client/src/mapping.ts b/compiler/packages/react-forgive/client/src/mapping.ts index 0505011711795..3ec01ef8f6288 100644 --- a/compiler/packages/react-forgive/client/src/mapping.ts +++ b/compiler/packages/react-forgive/client/src/mapping.ts @@ -1,3 +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. + */ + import * as vscode from 'vscode'; import {Position} from 'vscode-languageclient/node'; diff --git a/compiler/packages/react-forgive/server/src/compiler/compat.ts b/compiler/packages/react-forgive/server/src/compiler/compat.ts index 8b13f1df886ea..10271cbdcdc32 100644 --- a/compiler/packages/react-forgive/server/src/compiler/compat.ts +++ b/compiler/packages/react-forgive/server/src/compiler/compat.ts @@ -1,3 +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. + */ + import {SourceLocation} from 'babel-plugin-react-compiler/src'; import {type Range} from 'vscode-languageserver'; diff --git a/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts index 1738bbcd8c502..77a568662e48c 100644 --- a/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts +++ b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts @@ -1,3 +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. + */ + import {type AutoDepsDecorationsEvent} from 'babel-plugin-react-compiler/src/Entrypoint'; import {type Position} from 'vscode-languageserver-textdocument'; import {RequestType} from 'vscode-languageserver/node'; diff --git a/compiler/packages/react-forgive/server/src/utils/range.ts b/compiler/packages/react-forgive/server/src/utils/range.ts index 8a16f1bc096a4..5c164667c4f88 100644 --- a/compiler/packages/react-forgive/server/src/utils/range.ts +++ b/compiler/packages/react-forgive/server/src/utils/range.ts @@ -1,3 +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. + */ + import * as t from '@babel/types'; import {type Position} from 'vscode-languageserver/node'; diff --git a/compiler/packages/react-mcp-server/src/types/algolia.ts b/compiler/packages/react-mcp-server/src/types/algolia.ts index 68914076a362c..1921dd3f718f1 100644 --- a/compiler/packages/react-mcp-server/src/types/algolia.ts +++ b/compiler/packages/react-mcp-server/src/types/algolia.ts @@ -1,3 +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. + */ + // https://github.com/algolia/docsearch/blob/15ebcba606b281aa0dddc4ccb8feb19d396bf79e/packages/docsearch-react/src/types/DocSearchHit.ts type ContentType = | 'content' diff --git a/compiler/packages/react-mcp-server/tsup.config.ts b/compiler/packages/react-mcp-server/tsup.config.ts index eefc6ee0cee95..820410e20f651 100644 --- a/compiler/packages/react-mcp-server/tsup.config.ts +++ b/compiler/packages/react-mcp-server/tsup.config.ts @@ -1,3 +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. + */ + import {defineConfig} from 'tsup'; export default defineConfig({ diff --git a/compiler/scripts/release/prompt-for-otp.js b/compiler/scripts/release/prompt-for-otp.js index e69e4f1604f81..3cb1e419c784e 100644 --- a/compiler/scripts/release/prompt-for-otp.js +++ b/compiler/scripts/release/prompt-for-otp.js @@ -1,4 +1,10 @@ #!/usr/bin/env node +/** + * 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. + */ const prompt = require('prompt-promise'); diff --git a/compiler/scripts/release/publish.js b/compiler/scripts/release/publish.js index d367e331e309f..99c47384251cc 100755 --- a/compiler/scripts/release/publish.js +++ b/compiler/scripts/release/publish.js @@ -1,4 +1,10 @@ #!/usr/bin/env node +/** + * 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 strict'; diff --git a/compiler/scripts/release/shared/build-packages.js b/compiler/scripts/release/shared/build-packages.js index 21c88e3aae11e..0a5ac1f5c2b50 100644 --- a/compiler/scripts/release/shared/build-packages.js +++ b/compiler/scripts/release/shared/build-packages.js @@ -1,3 +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. + */ + const ora = require('ora'); const {execHelper} = require('./utils'); diff --git a/compiler/scripts/release/shared/packages.js b/compiler/scripts/release/shared/packages.js index 533041d119665..39970bdde6c39 100644 --- a/compiler/scripts/release/shared/packages.js +++ b/compiler/scripts/release/shared/packages.js @@ -1,3 +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. + */ + const PUBLISHABLE_PACKAGES = [ 'babel-plugin-react-compiler', 'eslint-plugin-react-compiler', diff --git a/compiler/scripts/release/shared/utils.js b/compiler/scripts/release/shared/utils.js index 8406e563303ba..bda2d28c032ce 100644 --- a/compiler/scripts/release/shared/utils.js +++ b/compiler/scripts/release/shared/utils.js @@ -1,3 +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. + */ + const cp = require('child_process'); const util = require('util');