24
printFunctionWithOutlined,
25
type LoggerEvent,
26
} from 'babel-plugin-react-compiler';
27
-import clsx from 'clsx';
27
import invariant from 'invariant';
28
import {useSnackbar} from 'notistack';
29
import {useDeferredValue, useMemo} from 'react';
46
PrintedCompilerPipelineValue,
47
} from './Output';
48
import {transformFromAstSync} from '@babel/core';
50
-import {useSearchParams} from 'next/navigation';
49
50
function parseInput(
51
input: string,
142
],
143
];
144
145
+function parseOptions(
146
+ source: string,
147
+ mode: 'compiler' | 'linter',
148
+ configOverrides: string,
149
+): PluginOptions {
150
+ // Extract the first line to quickly check for custom test directives
151
+ const pragma = source.substring(0, source.indexOf('\n'));
152
+
153
+ const parsedPragmaOptions = parseConfigPragmaForTests(pragma, {
154
+ compilationMode: 'infer',
155
+ environment:
156
+ mode === 'linter'
157
+ ? {
158
+ // enabled in compiler
159
+ validateRefAccessDuringRender: false,
160
+ // enabled in linter
161
+ validateNoSetStateInRender: true,
162
+ validateNoSetStateInEffects: true,
163
+ validateNoJSXInTryStatements: true,
164
+ validateNoImpureFunctionsInRender: true,
165
+ validateStaticComponents: true,
166
+ validateNoFreezingKnownMutableFunctions: true,
167
+ validateNoVoidUseMemo: true,
168
+ }
169
+ : {
170
+ /* use defaults for compiler mode */
171
+ },
172
+ });
173
+
174
+ // Parse config overrides from config editor
175
+ let configOverrideOptions: any = {};
176
+ const configMatch = configOverrides.match(/^\s*import.*?\n\n\((.*)\)/s);
177
+ // TODO: initialize store with URL params, not empty store
178
+ if (configOverrides.trim()) {
179
+ if (configMatch && configMatch[1]) {
180
+ const configString = configMatch[1].replace(/satisfies.*$/, '').trim();
181
+ configOverrideOptions = new Function(`return (${configString})`)();
182
+ } else {
183
+ throw new Error('Invalid override format');
184
+ }
185
+ }
186
+
187
+ const opts: PluginOptions = parsePluginOptions({
188
+ ...parsedPragmaOptions,
189
+ ...configOverrideOptions,
190
+ environment: {
191
+ ...parsedPragmaOptions.environment,
192
+ ...configOverrideOptions.environment,
193
+ customHooks: new Map([...COMMON_HOOKS]),
194
+ },
195
+ });
196
+
197
+ return opts;
198
+}
199
+
200
function compile(
201
source: string,
202
mode: 'compiler' | 'linter',
220
language = 'typescript';
221
}
222
let transformOutput;
223
+
224
+ let baseOpts: PluginOptions | null = null;
225
try {
171
- // Extract the first line to quickly check for custom test directives
172
- const pragma = source.substring(0, source.indexOf('\n'));
173
- const logIR = (result: CompilerPipelineValue): void => {
174
- switch (result.kind) {
175
- case 'ast': {
176
- break;
177
- }
178
- case 'hir': {
179
- upsert({
180
- kind: 'hir',
181
- fnName: result.value.id,
182
- name: result.name,
183
- value: printFunctionWithOutlined(result.value),
184
- });
185
- break;
186
- }
187
- case 'reactive': {
188
- upsert({
189
- kind: 'reactive',
190
- fnName: result.value.id,
191
- name: result.name,
192
- value: printReactiveFunctionWithOutlined(result.value),
193
- });
194
- break;
195
- }
196
- case 'debug': {
197
- upsert({
198
- kind: 'debug',
199
- fnName: null,
200
- name: result.name,
201
- value: result.value,
202
- });
203
- break;
204
- }
205
- default: {
206
- const _: never = result;
207
- throw new Error(`Unhandled result ${result}`);
226
+ baseOpts = parseOptions(source, mode, configOverrides);
227
+ } catch (err) {
228
+ error.details.push(
229
+ new CompilerErrorDetail({
230
+ category: ErrorCategory.Config,
231
+ reason: `Unexpected failure when transforming configs! \n${err}`,
232
+ loc: null,
233
+ suggestions: null,
234
+ }),
235
+ );
236
+ }
237
+ if (baseOpts) {
238
+ try {
239
+ const logIR = (result: CompilerPipelineValue): void => {
240
+ switch (result.kind) {
241
+ case 'ast': {
242
+ break;
243
+ }
244
+ case 'hir': {
245
+ upsert({
246
+ kind: 'hir',
247
+ fnName: result.value.id,
248
+ name: result.name,
249
+ value: printFunctionWithOutlined(result.value),
250
+ });
251
+ break;
252
+ }
253
+ case 'reactive': {
254
+ upsert({
255
+ kind: 'reactive',
256
+ fnName: result.value.id,
257
+ name: result.name,
258
+ value: printReactiveFunctionWithOutlined(result.value),
259
+ });
260
+ break;
261
+ }
262
+ case 'debug': {
263
+ upsert({
264
+ kind: 'debug',
265
+ fnName: null,
266
+ name: result.name,
267
+ value: result.value,
268
+ });
269
+ break;
270
+ }
271
+ default: {
272
+ const _: never = result;
273
+ throw new Error(`Unhandled result ${result}`);
274
+ }
275
}
209
- }
210
- };
211
- const parsedPragmaOptions = parseConfigPragmaForTests(pragma, {
212
- compilationMode: 'infer',
213
- environment:
214
- mode === 'linter'
215
- ? {
216
- // enabled in compiler
217
- validateRefAccessDuringRender: false,
218
- // enabled in linter
219
- validateNoSetStateInRender: true,
220
- validateNoSetStateInEffects: true,
221
- validateNoJSXInTryStatements: true,
222
- validateNoImpureFunctionsInRender: true,
223
- validateStaticComponents: true,
224
- validateNoFreezingKnownMutableFunctions: true,
225
- validateNoVoidUseMemo: true,
276
+ };
277
+ // Add logger options to the parsed options
278
+ const opts = {
279
+ ...baseOpts,
280
+ logger: {
281
+ debugLogIRs: logIR,
282
+ logEvent: (_filename: string | null, event: LoggerEvent) => {
283
+ if (event.kind === 'CompileError') {
284
+ otherErrors.push(event.detail);
285
}
227
- : {
228
- /* use defaults for compiler mode */
229
- },
230
- });
231
-
232
- // Parse config overrides from config editor
233
- let configOverrideOptions: any = {};
234
- const configMatch = configOverrides.match(/^\s*import.*?\n\n\((.*)\)/s);
235
- // TODO: initialize store with URL params, not empty store
236
- if (configOverrides.trim()) {
237
- if (configMatch && configMatch[1]) {
238
- const configString = configMatch[1].replace(/satisfies.*$/, '').trim();
239
- configOverrideOptions = new Function(`return (${configString})`)();
240
- } else {
241
- throw new Error('Invalid config overrides');
242
- }
243
- }
244
-
245
- const opts: PluginOptions = parsePluginOptions({
246
- ...parsedPragmaOptions,
247
- ...configOverrideOptions,
248
- environment: {
249
- ...parsedPragmaOptions.environment,
250
- ...configOverrideOptions.environment,
251
- customHooks: new Map([...COMMON_HOOKS]),
252
- },
253
- logger: {
254
- debugLogIRs: logIR,
255
- logEvent: (_filename: string | null, event: LoggerEvent) => {
256
- if (event.kind === 'CompileError') {
257
- otherErrors.push(event.detail);
258
- }
286
+ },
287
},
260
- },
261
- });
262
- transformOutput = invokeCompiler(source, language, opts);
263
- } catch (err) {
264
- /**
265
- * error might be an invariant violation or other runtime error
266
- * (i.e. object shape that is not CompilerError)
267
- */
268
- if (err instanceof CompilerError && err.details.length > 0) {
269
- error.merge(err);
270
- } else {
288
+ };
289
+ transformOutput = invokeCompiler(source, language, opts);
290
+ } catch (err) {
291
/**
272
- * Handle unexpected failures by logging (to get a stack trace)
273
- * and reporting
292
+ * error might be an invariant violation or other runtime error
293
+ * (i.e. object shape that is not CompilerError)
294
*/
275
- console.error(err);
276
- error.details.push(
277
- new CompilerErrorDetail({
278
- category: ErrorCategory.Invariant,
279
- reason: `Unexpected failure when transforming input! ${err}`,
280
- loc: null,
281
- suggestions: null,
282
- }),
283
- );
295
+ if (err instanceof CompilerError && err.details.length > 0) {
296
+ error.merge(err);
297
+ } else {
298
+ /**
299
+ * Handle unexpected failures by logging (to get a stack trace)
300
+ * and reporting
301
+ */
302
+ error.details.push(
303
+ new CompilerErrorDetail({
304
+ category: ErrorCategory.Invariant,
305
+ reason: `Unexpected failure when transforming input! \n${err}`,
306
+ loc: null,
307
+ suggestions: null,
308
+ }),
309
+ );
310
+ }
311
}
312
}
313
// Only include logger errors if there weren't other errors
377
}
378
return (
379
<>
353
- <div className="relative flex basis top-14">
354
- <ConfigEditor />
355
- <div className={clsx('relative sm:basis-1/4')}>
356
- <Input language={language} errors={errors} />
380
+ <div className="relative flex top-14">
381
+ <div className="flex-shrink-0">
382
+ <ConfigEditor />
383
</div>
358
- <div className={clsx('flex sm:flex flex-wrap')}>
359
- <Output store={deferredStore} compilerOutput={mergedOutput} />
384
+ <div className="flex flex-1 min-w-0">
385
+ <div className="flex-1 min-w-[550px] sm:min-w-0">
386
+ <Input language={language} errors={errors} />
387
+ </div>
388
+ <div className="flex-1 min-w-[550px] sm:min-w-0">
389
+ <Output store={deferredStore} compilerOutput={mergedOutput} />
390
+ </div>
391
</div>
392
</div>
393
</>