From 37a3b00cb71d21565619f27bcbde9fa9a556875b Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 1 Mar 2024 17:59:36 +0100 Subject: [PATCH 01/62] Implement jsx option --- docs/configuration-options/index.md | 8 +++++++ src/rollup/types.d.ts | 15 ++++++++++++ src/utils/options/mergeOptions.ts | 23 +++++++++++++++---- src/utils/options/normalizeInputOptions.ts | 22 +++++++++++++++++- src/utils/options/options.ts | 23 ++++++++++++++++--- src/utils/urls.ts | 1 + test/function/samples/options-hook/_config.js | 1 + test/misc/optionList.js | 4 ++-- 8 files changed, 87 insertions(+), 10 deletions(-) diff --git a/docs/configuration-options/index.md b/docs/configuration-options/index.md index 01bd1d9d2bb..f55a3551297 100755 --- a/docs/configuration-options/index.md +++ b/docs/configuration-options/index.md @@ -169,6 +169,14 @@ File names containing spaces can be specified by using quotes: rollup "main entry"="src/entry 1.js" "src/other entry.js" --format es ``` +### jsx + +| | | +| -------: | :----------------------------------------------- | +| Type: | `false \| "preserve" \| JsxPreset \| JsxOptions` | +| CLI: | `--jsx `/`--no-jsx` | +| Default: | `false` | + ### output.dir | | | diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 20a0488dd78..f375aa838c7 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -523,6 +523,18 @@ export interface Plugin extends OutputPlugin, Partial { api?: A; } +export type JsxPreset = 'react' | 'react-jsx'; + +export interface NormalizedJsxOptions { + factory: string; + fragmentFactory: string; + importSource: string | null; +} + +export interface JsxOptions extends Partial { + preset?: JsxPreset; +} + export type TreeshakingPreset = 'smallest' | 'safest' | 'recommended'; export interface NormalizedTreeshakingOptions { @@ -545,6 +557,7 @@ interface ManualChunkMeta { getModuleIds: () => IterableIterator; getModuleInfo: GetModuleInfo; } + export type GetManualChunk = (id: string, meta: ManualChunkMeta) => string | NullValue; export type ExternalOption = @@ -592,6 +605,7 @@ export interface InputOptions { experimentalLogSideEffects?: boolean; external?: ExternalOption; input?: InputOption; + jsx?: false | 'preserve' | JsxOptions; logLevel?: LogLevelOption; makeAbsoluteExternalsRelative?: boolean | 'ifRelativeSource'; maxParallelFileOps?: number; @@ -619,6 +633,7 @@ export interface NormalizedInputOptions { experimentalLogSideEffects: boolean; external: IsExternal; input: string[] | Record; + jsx: false | 'preserve' | NormalizedJsxOptions; logLevel: LogLevelOption; makeAbsoluteExternalsRelative: boolean | 'ifRelativeSource'; maxParallelFileOps: number; diff --git a/src/utils/options/mergeOptions.ts b/src/utils/options/mergeOptions.ts index 0e78b2374bb..26e6e32e4f6 100644 --- a/src/utils/options/mergeOptions.ts +++ b/src/utils/options/mergeOptions.ts @@ -8,10 +8,11 @@ import type { RollupCache, RollupOptions } from '../../rollup/types'; +import { EMPTY_ARRAY } from '../blank'; import { ensureArray } from '../ensureArray'; import { getLogger } from '../logger'; import { LOGLEVEL_INFO } from '../logging'; -import { URL_OUTPUT_GENERATEDCODE, URL_TREESHAKE } from '../urls'; +import { URL_JSX, URL_OUTPUT_GENERATEDCODE, URL_TREESHAKE } from '../urls'; import type { CommandConfigObject } from './normalizeInputOptions'; import { generatedCodePresets, @@ -134,6 +135,13 @@ function mergeInputOptions( experimentalLogSideEffects: getOption('experimentalLogSideEffects'), external: getExternal(config, overrides), input: getOption('input') || [], + jsx: getObjectOption( + config, + overrides, + 'jsx', + ['preserve'], + objectifyOptionWithPresets(treeshakePresets, 'jsx', URL_JSX, 'false, "preserve", ') + ), logLevel: getOption('logLevel'), makeAbsoluteExternalsRelative: getOption('makeAbsoluteExternalsRelative'), maxParallelFileOps: getOption('maxParallelFileOps'), @@ -150,6 +158,7 @@ function mergeInputOptions( config, overrides, 'treeshake', + EMPTY_ARRAY, objectifyOptionWithPresets(treeshakePresets, 'treeshake', URL_TREESHAKE, 'false, true, ') ), watch: getWatch(config, overrides) @@ -171,8 +180,13 @@ const getObjectOption = ( config: T, overrides: T, name: keyof T, + nonObjectValues: readonly unknown[], objectifyValue = objectifyOption -) => { +): any => { + const primitiveValue = overrides[name] ?? config[name]; + if (nonObjectValues.includes(primitiveValue)) { + return primitiveValue; + } const commandOption = normalizeObjectOptionValue(overrides[name], objectifyValue); const configOption = normalizeObjectOptionValue(config[name], objectifyValue); if (commandOption !== undefined) { @@ -182,7 +196,7 @@ const getObjectOption = ( }; export const getWatch = (config: InputOptions, overrides: InputOptions) => - config.watch !== false && getObjectOption(config, overrides, 'watch'); + config.watch !== false && getObjectOption(config, overrides, 'watch', EMPTY_ARRAY); export const isWatchEnabled = (optionValue: unknown): boolean => { if (Array.isArray(optionValue)) { @@ -221,7 +235,7 @@ async function mergeOutputOptions( ): Promise { const getOption = (name: keyof OutputOptions): any => overrides[name] ?? config[name]; const outputOptions: CompleteOutputOptions = { - amd: getObjectOption(config, overrides, 'amd'), + amd: getObjectOption(config, overrides, 'amd', EMPTY_ARRAY), assetFileNames: getOption('assetFileNames'), banner: getOption('banner'), chunkFileNames: getOption('chunkFileNames'), @@ -244,6 +258,7 @@ async function mergeOutputOptions( config, overrides, 'generatedCode', + EMPTY_ARRAY, objectifyOptionWithPresets( generatedCodePresets, 'output.generatedCode', diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index 0342b71d801..5adf02b1ecf 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -11,10 +11,11 @@ import { getLogger } from '../logger'; import { LOGLEVEL_INFO } from '../logging'; import { error, logInvalidOption } from '../logs'; import { resolve } from '../path'; -import { URL_TREESHAKE, URL_TREESHAKE_MODULESIDEEFFECTS } from '../urls'; +import { URL_JSX, URL_TREESHAKE, URL_TREESHAKE_MODULESIDEEFFECTS } from '../urls'; import { getOnLog, getOptionWithPreset, + jsxPresets, normalizePluginOption, treeshakePresets, warnUnknownOptions @@ -50,6 +51,7 @@ export async function normalizeInputOptions( experimentalLogSideEffects: config.experimentalLogSideEffects || false, external: getIdMatcher(config.external), input: getInput(config), + jsx: getJsx(config), logLevel, makeAbsoluteExternalsRelative: config.makeAbsoluteExternalsRelative ?? 'ifRelativeSource', maxParallelFileOps, @@ -114,6 +116,24 @@ const getInput = (config: InputOptions): NormalizedInputOptions['input'] => { return configInput == null ? [] : typeof configInput === 'string' ? [configInput] : configInput; }; +const getJsx = (config: InputOptions): NormalizedInputOptions['jsx'] => { + const configJsx = config.jsx; + if (!configJsx) return false; + if (configJsx === 'preserve') return 'preserve'; + const configWithPreset = getOptionWithPreset( + configJsx, + jsxPresets, + 'jsx', + URL_JSX, + 'false, "preserve", ' + ); + return { + factory: configWithPreset.factory || 'React.createElement', + fragmentFactory: configWithPreset.fragmentFactory || 'React.Fragment', + importSource: configWithPreset.importSource || null + }; +}; + const getMaxParallelFileOps = ( config: InputOptions ): NormalizedInputOptions['maxParallelFileOps'] => { diff --git a/src/utils/options/options.ts b/src/utils/options/options.ts index 2fe3cea1af2..995c2a67949 100644 --- a/src/utils/options/options.ts +++ b/src/utils/options/options.ts @@ -5,6 +5,7 @@ import type { LogLevelOption, NormalizedGeneratedCodeOptions, NormalizedInputOptions, + NormalizedJsxOptions, NormalizedOutputOptions, NormalizedTreeshakingOptions, OutputOptions, @@ -136,6 +137,21 @@ export const treeshakePresets: { } }; +export const jsxPresets: { + [key in NonNullable['preset']>]: NormalizedJsxOptions; +} = { + react: { + factory: 'React.createElement', + fragmentFactory: 'React.Fragment', + importSource: null + }, + 'react-jsx': { + factory: 'jsx', + fragmentFactory: 'Fragment', + importSource: 'react' + } +}; + export const generatedCodePresets: { [key in NonNullable< ObjectValue['preset'] @@ -159,7 +175,8 @@ export const generatedCodePresets: { type ObjectOptionWithPresets = | Partial - | Partial; + | Partial + | Partial; export const objectifyOption = (value: unknown): Record => value && typeof value === 'object' ? (value as Record) : {}; @@ -197,7 +214,7 @@ export const getOptionWithPreset = ( optionName: string, urlSnippet: string, additionalValues: string -): Record => { +): T => { const presetName: string | undefined = (value as any)?.preset; if (presetName) { const preset = presets[presetName]; @@ -214,7 +231,7 @@ export const getOptionWithPreset = ( ); } } - return objectifyOptionWithPresets(presets, optionName, urlSnippet, additionalValues)(value); + return objectifyOptionWithPresets(presets, optionName, urlSnippet, additionalValues)(value) as T; }; export const normalizePluginOption: { diff --git a/src/utils/urls.ts b/src/utils/urls.ts index 13dc372c49b..3b94e774b83 100644 --- a/src/utils/urls.ts +++ b/src/utils/urls.ts @@ -8,6 +8,7 @@ export const URL_SOURCEMAP_IS_LIKELY_TO_BE_INCORRECT = 'troubleshooting/#warning-sourcemap-is-likely-to-be-incorrect'; // configuration-options +export const URL_JSX = 'configuration-options/#jsx'; export const URL_MAXPARALLELFILEOPS = 'configuration-options/#maxparallelfileops'; export const URL_OUTPUT_AMD_ID = 'configuration-options/#output-amd-id'; export const URL_OUTPUT_AMD_BASEPATH = 'configuration-options/#output-amd-basepath'; diff --git a/test/function/samples/options-hook/_config.js b/test/function/samples/options-hook/_config.js index 72badede7dd..ef6bdc0398e 100644 --- a/test/function/samples/options-hook/_config.js +++ b/test/function/samples/options-hook/_config.js @@ -15,6 +15,7 @@ module.exports = defineTest({ experimentalCacheExpiry: 10, experimentalLogSideEffects: false, input: ['used'], + jsx: false, logLevel: 'info', makeAbsoluteExternalsRelative: 'ifRelativeSource', maxParallelFileOps: 20, diff --git a/test/misc/optionList.js b/test/misc/optionList.js index 7ba1fee5767..72caf132d10 100644 --- a/test/misc/optionList.js +++ b/test/misc/optionList.js @@ -1,6 +1,6 @@ exports.input = - 'cache, context, experimentalCacheExpiry, experimentalLogSideEffects, external, input, logLevel, makeAbsoluteExternalsRelative, maxParallelFileOps, moduleContext, onLog, onwarn, perf, plugins, preserveEntrySignatures, preserveSymlinks, shimMissingExports, strictDeprecations, treeshake, watch'; + 'cache, context, experimentalCacheExpiry, experimentalLogSideEffects, external, input, jsx, logLevel, makeAbsoluteExternalsRelative, maxParallelFileOps, moduleContext, onLog, onwarn, perf, plugins, preserveEntrySignatures, preserveSymlinks, shimMissingExports, strictDeprecations, treeshake, watch'; exports.flags = - 'amd, assetFileNames, banner, bundleConfigAsCjs, c, cache, chunkFileNames, compact, config, configPlugin, context, d, dir, dynamicImportInCjs, e, entryFileNames, environment, esModule, experimentalCacheExpiry, experimentalLogSideEffects, experimentalMinChunkSize, exports, extend, external, externalImportAssertions, externalImportAttributes, externalLiveBindings, f, failAfterWarnings, file, filterLogs, footer, forceExit, format, freeze, g, generatedCode, globals, h, hashCharacters, hoistTransitiveImports, i, importAttributesKey, indent, inlineDynamicImports, input, interop, intro, logLevel, m, makeAbsoluteExternalsRelative, manualChunks, maxParallelFileOps, minifyInternalExports, moduleContext, n, name, noConflict, o, onLog, onwarn, outro, p, paths, perf, plugin, plugins, preserveEntrySignatures, preserveModules, preserveModulesRoot, preserveSymlinks, reexportProtoFromExternal, sanitizeFileName, shimMissingExports, silent, sourcemap, sourcemapBaseUrl, sourcemapExcludeSources, sourcemapFile, sourcemapFileNames, stdin, strict, strictDeprecations, systemNullSetters, treeshake, v, validate, virtualDirname, w, waitForBundleInput, watch'; + 'amd, assetFileNames, banner, bundleConfigAsCjs, c, cache, chunkFileNames, compact, config, configPlugin, context, d, dir, dynamicImportInCjs, e, entryFileNames, environment, esModule, experimentalCacheExpiry, experimentalLogSideEffects, experimentalMinChunkSize, exports, extend, external, externalImportAssertions, externalImportAttributes, externalLiveBindings, f, failAfterWarnings, file, filterLogs, footer, forceExit, format, freeze, g, generatedCode, globals, h, hashCharacters, hoistTransitiveImports, i, importAttributesKey, indent, inlineDynamicImports, input, interop, intro, jsx, logLevel, m, makeAbsoluteExternalsRelative, manualChunks, maxParallelFileOps, minifyInternalExports, moduleContext, n, name, noConflict, o, onLog, onwarn, outro, p, paths, perf, plugin, plugins, preserveEntrySignatures, preserveModules, preserveModulesRoot, preserveSymlinks, reexportProtoFromExternal, sanitizeFileName, shimMissingExports, silent, sourcemap, sourcemapBaseUrl, sourcemapExcludeSources, sourcemapFile, sourcemapFileNames, stdin, strict, strictDeprecations, systemNullSetters, treeshake, v, validate, virtualDirname, w, waitForBundleInput, watch'; exports.output = 'amd, assetFileNames, banner, chunkFileNames, compact, dir, dynamicImportInCjs, entryFileNames, esModule, experimentalMinChunkSize, exports, extend, externalImportAssertions, externalImportAttributes, externalLiveBindings, file, footer, format, freeze, generatedCode, globals, hashCharacters, hoistTransitiveImports, importAttributesKey, indent, inlineDynamicImports, interop, intro, manualChunks, minifyInternalExports, name, noConflict, outro, paths, plugins, preserveModules, preserveModulesRoot, reexportProtoFromExternal, sanitizeFileName, sourcemap, sourcemapBaseUrl, sourcemapExcludeSources, sourcemapFile, sourcemapFileNames, sourcemapIgnoreList, sourcemapPathTransform, strict, systemNullSetters, validate, virtualDirname'; From 5fb52889d5cc88c12a58461ed520f766373d314c Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 2 Mar 2024 08:07:21 +0100 Subject: [PATCH 02/62] Add tests --- test/form/samples/jsx/preserves-jsx/_config.js | 8 ++++++++ test/form/samples/jsx/preserves-jsx/_expected.js | 4 ++++ test/form/samples/jsx/preserves-jsx/main.js | 4 ++++ test/form/samples/jsx/transpiles-react/_config.js | 8 ++++++++ test/form/samples/jsx/transpiles-react/_expected.js | 4 ++++ test/form/samples/jsx/transpiles-react/main.js | 4 ++++ 6 files changed, 32 insertions(+) create mode 100644 test/form/samples/jsx/preserves-jsx/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx/main.js create mode 100644 test/form/samples/jsx/transpiles-react/_config.js create mode 100644 test/form/samples/jsx/transpiles-react/_expected.js create mode 100644 test/form/samples/jsx/transpiles-react/main.js diff --git a/test/form/samples/jsx/preserves-jsx/_config.js b/test/form/samples/jsx/preserves-jsx/_config.js new file mode 100644 index 00000000000..deba7dd3240 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX output', + options: { + external: ['react'], + jsx: 'preserve' + } +}); diff --git a/test/form/samples/jsx/preserves-jsx/_expected.js b/test/form/samples/jsx/preserves-jsx/_expected.js new file mode 100644 index 00000000000..6dc07da2a1d --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx/_expected.js @@ -0,0 +1,4 @@ +import React from "react"; + +const Foo = () => {}; +export const result = ; diff --git a/test/form/samples/jsx/preserves-jsx/main.js b/test/form/samples/jsx/preserves-jsx/main.js new file mode 100644 index 00000000000..6dc07da2a1d --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx/main.js @@ -0,0 +1,4 @@ +import React from "react"; + +const Foo = () => {}; +export const result = ; diff --git a/test/form/samples/jsx/transpiles-react/_config.js b/test/form/samples/jsx/transpiles-react/_config.js new file mode 100644 index 00000000000..7dbf6431642 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX for react', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-react/_expected.js b/test/form/samples/jsx/transpiles-react/_expected.js new file mode 100644 index 00000000000..8250e6193c2 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react/_expected.js @@ -0,0 +1,4 @@ +import React from "react"; + +const Foo = () => {}; +export const result = React.createElement(Foo, null); diff --git a/test/form/samples/jsx/transpiles-react/main.js b/test/form/samples/jsx/transpiles-react/main.js new file mode 100644 index 00000000000..6dc07da2a1d --- /dev/null +++ b/test/form/samples/jsx/transpiles-react/main.js @@ -0,0 +1,4 @@ +import React from "react"; + +const Foo = () => {}; +export const result = ; From eb86704a275b3fa487444b345e6062d8df082282 Mon Sep 17 00:00:00 2001 From: Martin Idel Date: Sat, 2 Mar 2024 11:46:05 +0100 Subject: [PATCH 03/62] Pass jsx options to SWC Signed-off-by: Martin Idel --- browser/src/wasm.ts | 3 ++- native.d.ts | 4 ++-- rust/bindings_napi/src/lib.rs | 9 ++++++--- rust/bindings_wasm/src/lib.rs | 4 ++-- rust/parse_ast/src/lib.rs | 3 ++- src/Bundle.ts | 2 +- src/Module.ts | 4 ++-- src/rollup/types.d.ts | 4 ++-- src/utils/parseAst.ts | 8 ++++---- wasm/bindings_wasm.d.ts | 5 +++-- wasm/bindings_wasm_bg.wasm.d.ts | 2 +- 11 files changed, 27 insertions(+), 21 deletions(-) diff --git a/browser/src/wasm.ts b/browser/src/wasm.ts index c663b8ebd2c..afc48773f6d 100644 --- a/browser/src/wasm.ts +++ b/browser/src/wasm.ts @@ -5,7 +5,8 @@ import { parse } from '../../wasm/bindings_wasm.js'; export async function parseAsync( code: string, allowReturnOutsideFunction: boolean, + jsx: boolean, _signal?: AbortSignal | undefined | null ) { - return parse(code, allowReturnOutsideFunction); + return parse(code, allowReturnOutsideFunction, jsx); } diff --git a/native.d.ts b/native.d.ts index 0085313ac22..0047a3ee494 100644 --- a/native.d.ts +++ b/native.d.ts @@ -3,8 +3,8 @@ /* auto-generated by NAPI-RS */ -export declare function parse(code: string, allowReturnOutsideFunction: boolean): Buffer -export declare function parseAsync(code: string, allowReturnOutsideFunction: boolean, signal?: AbortSignal | undefined | null): Promise +export declare function parse(code: string, allowReturnOutsideFunction: boolean, jsx: boolean): Buffer +export declare function parseAsync(code: string, allowReturnOutsideFunction: boolean, jsx: boolean, signal?: AbortSignal | undefined | null): Promise export declare function xxhashBase64Url(input: Uint8Array): string export declare function xxhashBase36(input: Uint8Array): string export declare function xxhashBase16(input: Uint8Array): string diff --git a/rust/bindings_napi/src/lib.rs b/rust/bindings_napi/src/lib.rs index 219334231ab..58286e0e4b6 100644 --- a/rust/bindings_napi/src/lib.rs +++ b/rust/bindings_napi/src/lib.rs @@ -12,6 +12,7 @@ static ALLOC: mimalloc_rust::GlobalMiMalloc = mimalloc_rust::GlobalMiMalloc; pub struct ParseTask { pub code: String, pub allow_return_outside_function: bool, + pub jsx: bool, } #[napi] @@ -20,7 +21,7 @@ impl Task for ParseTask { type JsValue = Buffer; fn compute(&mut self) -> Result { - Ok(parse_ast(self.code.clone(), self.allow_return_outside_function).into()) + Ok(parse_ast(self.code.clone(), self.allow_return_outside_function, self.jsx).into()) } fn resolve(&mut self, _env: Env, output: Self::Output) -> Result { @@ -29,20 +30,22 @@ impl Task for ParseTask { } #[napi] -pub fn parse(code: String, allow_return_outside_function: bool) -> Buffer { - parse_ast(code, allow_return_outside_function).into() +pub fn parse(code: String, allow_return_outside_function: bool, jsx: bool) -> Buffer { + parse_ast(code, allow_return_outside_function, jsx).into() } #[napi] pub fn parse_async( code: String, allow_return_outside_function: bool, + jsx: bool, signal: Option, ) -> AsyncTask { AsyncTask::with_optional_signal( ParseTask { code, allow_return_outside_function, + jsx, }, signal, ) diff --git a/rust/bindings_wasm/src/lib.rs b/rust/bindings_wasm/src/lib.rs index 23e0f0d654a..197809bae52 100644 --- a/rust/bindings_wasm/src/lib.rs +++ b/rust/bindings_wasm/src/lib.rs @@ -3,8 +3,8 @@ use parse_ast::parse_ast; use wasm_bindgen::prelude::*; #[wasm_bindgen] -pub fn parse(code: String, allow_return_outside_function: bool) -> Vec { - parse_ast(code, allow_return_outside_function) +pub fn parse(code: String, allow_return_outside_function: bool, jsx: bool) -> Vec { + parse_ast(code, allow_return_outside_function, jsx) } #[wasm_bindgen(js_name=xxhashBase64Url)] diff --git a/rust/parse_ast/src/lib.rs b/rust/parse_ast/src/lib.rs index 6ffe5074dc4..ff8790a93ae 100644 --- a/rust/parse_ast/src/lib.rs +++ b/rust/parse_ast/src/lib.rs @@ -17,7 +17,7 @@ mod ast_nodes; mod convert_ast; mod error_emit; -pub fn parse_ast(code: String, allow_return_outside_function: bool) -> Vec { +pub fn parse_ast(code: String, allow_return_outside_function: bool, jsx: bool) -> Vec { let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let target = EsVersion::EsNext; let syntax = Syntax::Es(EsSyntax { @@ -25,6 +25,7 @@ pub fn parse_ast(code: String, allow_return_outside_function: bool) -> Vec { import_attributes: true, explicit_resource_management: true, decorators: true, + jsx, ..Default::default() }); diff --git a/src/Bundle.ts b/src/Bundle.ts index 5e055f1d6e2..3731f7093d3 100644 --- a/src/Bundle.ts +++ b/src/Bundle.ts @@ -150,7 +150,7 @@ export default class Bundle { for (const file of Object.values(bundle)) { if ('code' in file) { try { - parseAst(file.code); + parseAst(file.code, { jsx: this.inputOptions.jsx !== false }); } catch (error_: any) { this.inputOptions.onLog(LOGLEVEL_WARN, logChunkInvalid(file, error_)); } diff --git a/src/Module.ts b/src/Module.ts index 9108eeb81c5..302788601a4 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -906,7 +906,7 @@ export default class Module { } else { // Measuring asynchronous code does not provide reasonable results timeEnd('generate ast', 3); - const astBuffer = await parseAsync(code, false); + const astBuffer = await parseAsync(code, false, this.options.jsx !== false); timeStart('generate ast', 3); this.ast = convertProgram(astBuffer, programParent, this.scope); // Make lazy and apply LRU cache to not hog the memory @@ -1386,7 +1386,7 @@ export default class Module { private tryParse() { try { - return parseAst(this.info.code!); + return parseAst(this.info.code!, { jsx: this.options.jsx !== false }); } catch (error_: any) { return this.error(logModuleParseError(error_, this.id), error_.pos); } diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index f375aa838c7..4aff69892a0 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -220,7 +220,7 @@ type LoggingFunctionWithPosition = ( export type ParseAst = ( input: string, - options?: { allowReturnOutsideFunction?: boolean } + options?: { allowReturnOutsideFunction?: boolean; jsx?: boolean } ) => ProgramNode; // declare AbortSignal here for environments without DOM lib or @types/node @@ -231,7 +231,7 @@ declare global { export type ParseAstAsync = ( input: string, - options?: { allowReturnOutsideFunction?: boolean; signal?: AbortSignal } + options?: { allowReturnOutsideFunction?: boolean; jsx?: boolean; signal?: AbortSignal } ) => Promise; export interface PluginContext extends MinimalPluginContext { diff --git a/src/utils/parseAst.ts b/src/utils/parseAst.ts index 75e90c6f065..60ef163147d 100644 --- a/src/utils/parseAst.ts +++ b/src/utils/parseAst.ts @@ -3,10 +3,10 @@ import type { ParseAst, ParseAstAsync } from '../rollup/types'; import { convertProgram } from './bufferToAst'; import { getAstBuffer } from './getAstBuffer'; -export const parseAst: ParseAst = (input, { allowReturnOutsideFunction = false } = {}) => - convertProgram(getAstBuffer(parse(input, allowReturnOutsideFunction))); +export const parseAst: ParseAst = (input, { allowReturnOutsideFunction = false, jsx = false } = {}) => + convertProgram(getAstBuffer(parse(input, allowReturnOutsideFunction, jsx))); export const parseAstAsync: ParseAstAsync = async ( input, - { allowReturnOutsideFunction = false, signal } = {} -) => convertProgram(getAstBuffer(await parseAsync(input, allowReturnOutsideFunction, signal))); + { allowReturnOutsideFunction = false, jsx = false, signal } = {} +) => convertProgram(getAstBuffer(await parseAsync(input, allowReturnOutsideFunction, jsx, signal))); diff --git a/wasm/bindings_wasm.d.ts b/wasm/bindings_wasm.d.ts index 8bd3e23c94b..2c00d9fee76 100644 --- a/wasm/bindings_wasm.d.ts +++ b/wasm/bindings_wasm.d.ts @@ -3,9 +3,10 @@ /** * @param {string} code * @param {boolean} allow_return_outside_function +* @param {boolean} jsx * @returns {Uint8Array} */ -export function parse(code: string, allow_return_outside_function: boolean): Uint8Array; +export function parse(code: string, allow_return_outside_function: boolean, jsx: boolean): Uint8Array; /** * @param {Uint8Array} input * @returns {string} @@ -26,7 +27,7 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl export interface InitOutput { readonly memory: WebAssembly.Memory; - readonly parse: (a: number, b: number, c: number, d: number) => void; + readonly parse: (a: number, b: number, c: number, d: number, e: number) => void; readonly xxhashBase64Url: (a: number, b: number) => void; readonly xxhashBase36: (a: number, b: number) => void; readonly xxhashBase16: (a: number, b: number) => void; diff --git a/wasm/bindings_wasm_bg.wasm.d.ts b/wasm/bindings_wasm_bg.wasm.d.ts index d9dad8cd64d..7e56b53ff93 100644 --- a/wasm/bindings_wasm_bg.wasm.d.ts +++ b/wasm/bindings_wasm_bg.wasm.d.ts @@ -1,7 +1,7 @@ /* tslint:disable */ /* eslint-disable */ export const memory: WebAssembly.Memory; -export function parse(a: number, b: number, c: number, d: number): void; +export function parse(a: number, b: number, c: number, d: number, e: number): void; export function xxhashBase64Url(a: number, b: number): void; export function xxhashBase36(a: number, b: number): void; export function xxhashBase16(a: number, b: number): void; From 72e9b57a010b032f3b9a1f8ce75d6ffdadddc2a5 Mon Sep 17 00:00:00 2001 From: Felix Huttmann Date: Sat, 2 Mar 2024 12:30:22 +0100 Subject: [PATCH 04/62] Add JsxElement to ast-types --- rust/parse_ast/src/convert_ast/converter.rs | 31 ++++++-- .../convert_ast/converter/ast_constants.rs | 28 +++---- .../src/convert_ast/converter/ast_macros.rs | 75 +++++++++++++------ scripts/ast-types.js | 8 ++ src/ast/bufferParsers.ts | 13 ++++ src/ast/childNodeKeys.ts | 1 + src/ast/nodes/JsxElement.ts | 9 +++ src/ast/nodes/NodeType.ts | 2 + src/ast/nodes/index.ts | 2 + src/utils/bufferToAst.ts | 13 ++++ 10 files changed, 137 insertions(+), 45 deletions(-) create mode 100644 src/ast/nodes/JsxElement.ts diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index b5d55d15505..03bea2584a3 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,10 +1,5 @@ use swc_common::Span; -use swc_ecma_ast::{ - AssignTarget, AssignTargetPat, CallExpr, Callee, ClassMember, Decl, ExportSpecifier, Expr, - ExprOrSpread, ForHead, ImportSpecifier, Lit, ModuleDecl, ModuleExportName, ModuleItem, - NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, - SimpleAssignTarget, Stmt, VarDeclOrExpr, -}; +use swc_ecma_ast::{AssignTarget, AssignTargetPat, CallExpr, Callee, ClassMember, Decl, ExportSpecifier, Expr, ExprOrSpread, ForHead, ImportSpecifier, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, JSXElement}; use crate::ast_nodes::call_expression::StoredCallee; use crate::ast_nodes::variable_declaration::VariableDeclaration; @@ -362,7 +357,9 @@ impl<'a> AstConverter<'a> { Expr::JSXMember(_) => unimplemented!("Cannot convert Expr::JSXMember"), Expr::JSXNamespacedName(_) => unimplemented!("Cannot convert Expr::JSXNamespacedName"), Expr::JSXEmpty(_) => unimplemented!("Cannot convert Expr::JSXEmpty"), - Expr::JSXElement(_) => unimplemented!("Cannot convert Expr::JSXElement"), + Expr::JSXElement(jsx_element) => { + self.convert_jsx_element(jsx_element); + }, Expr::JSXFragment(_) => unimplemented!("Cannot convert Expr::JSXFragment"), Expr::TsTypeAssertion(_) => unimplemented!("Cannot convert Expr::TsTypeAssertion"), Expr::TsConstAssertion(_) => unimplemented!("Cannot convert Expr::TsConstAssertion"), @@ -654,6 +651,26 @@ impl<'a> AstConverter<'a> { } } } + + fn convert_jsx_element(&mut self, jsx_element: &JSXElement) { + panic!("JSXElement not supported"); + /* let end_position = self.add_type_and_start( + &TYPE_JSX_ELEMENT_EXPRESSION, + &jsx_element.span, + JSX_ELEMENT_EXPRESSION_RESERVED_BYTES, + false, + ); + self.store_identifier() + // argument + jsx_element.opening.as_ref().map(|expression| { + + + self.update_reference_position(end_position + YIELD_EXPRESSION_ARGUMENT_OFFSET); + self.convert_expression(expression) + }); + // end + self.add_end(end_position, &jsx_element.span);*/ + } } pub fn convert_annotation(buffer: &mut Vec, annotation: &ConvertedAnnotation) { diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index 72f6335f85f..6e5b8c77d68 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -24,20 +24,20 @@ pub const TYPE_IDENTIFIER: [u8; 4] = 34u32.to_ne_bytes(); pub const TYPE_IMPORT_ATTRIBUTE: [u8; 4] = 36u32.to_ne_bytes(); pub const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); pub const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 49u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 51u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 52u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 53u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 57u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 58u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 59u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 60u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 63u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 70u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 73u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 76u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 77u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 51u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 52u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 53u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 54u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 58u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 59u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 60u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 61u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 71u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 74u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 77u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 78u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index 9270789b436..ecd17d50c6e 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -315,11 +315,38 @@ macro_rules! store_import_specifier { }; } +#[macro_export] +macro_rules! store_jsx_element { + ($self:expr, span => $span:expr, openingElement => [$openingElement_value:expr, $openingElement_converter:ident], closingElement => [$closingElement_value:expr, $closingElement_converter:ident], children => [$children_value:expr, $children_converter:ident]) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&42u32.to_ne_bytes(), &$span, 16, false); + // openingElement + $self.update_reference_position(end_position + 4); + $self.$openingElement_converter(&$openingElement_value); + // closingElement + if let Some(value) = $closingElement_value.as_ref() { + $self.update_reference_position(end_position + 8); + $self.$closingElement_converter(value); + } + // children + $self.convert_item_list( + &$children_value, + end_position + 12, + |ast_converter, node| { + ast_converter.$children_converter(node); + true + }, + ); + // end + $self.add_end(end_position, &$span); + }; +} + #[macro_export] macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&42u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&43u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +362,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&43u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&44u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +377,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &44u32.to_ne_bytes(), + &45u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +393,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&45u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&46u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +403,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&46u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&47u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +420,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&47u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&48u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +434,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&48u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&49u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +450,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&54u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +469,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +488,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +500,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&62u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +515,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&62u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&63u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +534,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&64u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +549,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +559,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +583,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +601,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +618,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &69u32.to_ne_bytes(), + &70u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +640,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +650,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +663,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +680,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &75u32.to_ne_bytes(), + &76u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +702,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +719,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &79u32.to_ne_bytes(), + &80u32.to_ne_bytes(), &$span, 12, false, diff --git a/scripts/ast-types.js b/scripts/ast-types.js index fbfa8f80770..946522976a7 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -388,6 +388,14 @@ export const AST_NODES = { imported: 'local' } }, + JsxElement: { + estreeType: 'any', + fields: [ + ['openingElement', 'Node'], + ['closingElement', 'OptionalNode'], + ['children', 'NodeList'] + ] + }, LabeledStatement: { fields: [ ['label', 'Node'], diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index b197bd23ece..bafd883771d 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -48,6 +48,7 @@ import ImportDefaultSpecifier from './nodes/ImportDefaultSpecifier'; import ImportExpression from './nodes/ImportExpression'; import ImportNamespaceSpecifier from './nodes/ImportNamespaceSpecifier'; import ImportSpecifier from './nodes/ImportSpecifier'; +import JsxElement from './nodes/JsxElement'; import LabeledStatement from './nodes/LabeledStatement'; import Literal from './nodes/Literal'; import LogicalExpression from './nodes/LogicalExpression'; @@ -141,6 +142,7 @@ const nodeTypeStrings = [ 'ImportExpression', 'ImportNamespaceSpecifier', 'ImportSpecifier', + 'JsxElement', 'LabeledStatement', 'Literal', 'Literal', @@ -224,6 +226,7 @@ const nodeConstructors: (typeof NodeBase)[] = [ ImportExpression, ImportNamespaceSpecifier, ImportSpecifier, + JsxElement, LabeledStatement, Literal, Literal, @@ -563,6 +566,16 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ node.imported = importedPosition === 0 ? node.local : convertNode(node, scope, importedPosition, buffer); }, + function jsxElement(node: JsxElement, position, buffer) { + const { scope } = node; + node.openingElement = convertNode(node, scope, buffer[position], buffer); + const closingElementPosition = buffer[position + 1]; + node.closingElement = + closingElementPosition === 0 + ? null + : convertNode(node, scope, closingElementPosition, buffer); + node.children = convertNodeList(node, scope, buffer[position + 2], buffer); + }, function labeledStatement(node: LabeledStatement, position, buffer) { const { scope } = node; node.label = convertNode(node, scope, buffer[position], buffer); diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index e6ab43b65af..edec2767a55 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -41,6 +41,7 @@ export const childNodeKeys: Record = { ImportExpression: ['source', 'options'], ImportNamespaceSpecifier: ['local'], ImportSpecifier: ['imported', 'local'], + JsxElement: ['openingElement', 'closingElement', 'children'], LabeledStatement: ['label', 'body'], Literal: [], LogicalExpression: ['left', 'right'], diff --git a/src/ast/nodes/JsxElement.ts b/src/ast/nodes/JsxElement.ts new file mode 100644 index 00000000000..d89dec4b247 --- /dev/null +++ b/src/ast/nodes/JsxElement.ts @@ -0,0 +1,9 @@ +import type * as NodeType from './NodeType'; +import { type ExpressionNode, NodeBase } from './shared/Node'; + +export default class JsxElement extends NodeBase { + declare closingElement: unknown; + declare openingElement: unknown; + declare type: NodeType.tJsxElement; + declare children: ExpressionNode[]; +} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index f3dfbb7d794..b83298b8329 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -40,6 +40,7 @@ export type tImportDefaultSpecifier = 'ImportDefaultSpecifier'; export type tImportExpression = 'ImportExpression'; export type tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export type tImportSpecifier = 'ImportSpecifier'; +export type tJsxElement = 'JsxElement'; export type tLabeledStatement = 'LabeledStatement'; export type tLiteral = 'Literal'; export type tLogicalExpression = 'LogicalExpression'; @@ -115,6 +116,7 @@ export const ImportDefaultSpecifier: tImportDefaultSpecifier = 'ImportDefaultSpe export const ImportExpression: tImportExpression = 'ImportExpression'; export const ImportNamespaceSpecifier: tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export const ImportSpecifier: tImportSpecifier = 'ImportSpecifier'; +export const JsxElement: tJsxElement = 'JsxElement'; export const LabeledStatement: tLabeledStatement = 'LabeledStatement'; export const Literal: tLiteral = 'Literal'; export const LogicalExpression: tLogicalExpression = 'LogicalExpression'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 56ef603ba67..92f57f1e7fb 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -40,6 +40,7 @@ import ImportDefaultSpecifier from './ImportDefaultSpecifier'; import ImportExpression from './ImportExpression'; import ImportNamespaceSpecifier from './ImportNamespaceSpecifier'; import ImportSpecifier from './ImportSpecifier'; +import JsxElement from './JsxElement'; import LabeledStatement from './LabeledStatement'; import Literal from './Literal'; import LogicalExpression from './LogicalExpression'; @@ -118,6 +119,7 @@ export const nodeConstructors: Record = { ImportExpression, ImportNamespaceSpecifier, ImportSpecifier, + JsxElement, LabeledStatement, Literal, LogicalExpression, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index bf870cc1d5e..7d565532876 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -450,6 +450,18 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ local }; }, + function jsxElement(position, buffer): JsxElementNode { + const closingElementPosition = buffer[position + 3]; + return { + type: 'JsxElement', + start: buffer[position], + end: buffer[position + 1], + openingElement: convertNode(buffer[position + 2], buffer), + closingElement: + closingElementPosition === 0 ? null : convertNode(closingElementPosition, buffer), + children: convertNodeList(buffer[position + 4], buffer) + }; + }, function labeledStatement(position, buffer): LabeledStatementNode { return { type: 'LabeledStatement', @@ -895,6 +907,7 @@ export type ImportExpressionNode = RollupAstNode< >; export type ImportNamespaceSpecifierNode = RollupAstNode; export type ImportSpecifierNode = RollupAstNode; +export type JsxElementNode = RollupAstNode; export type LabeledStatementNode = RollupAstNode; export type LiteralBigIntNode = RollupAstNode; export type LiteralBooleanNode = RollupAstNode; From 9aa3d5ccdb416afec0374313002021ba9da62bb5 Mon Sep 17 00:00:00 2001 From: Alexander Droll Date: Sat, 2 Mar 2024 15:54:51 +0100 Subject: [PATCH 05/62] Add JsxOpeningElement --- rust/bindings_napi/src/lib.rs | 9 +- rust/parse_ast/src/convert_ast/converter.rs | 110 ++++++++++++++---- .../convert_ast/converter/ast_constants.rs | 43 ++++--- .../src/convert_ast/converter/ast_macros.rs | 89 ++++++-------- scripts/ast-types.js | 17 ++- src/ast/bufferParsers.ts | 16 +++ src/ast/childNodeKeys.ts | 2 + src/ast/nodes/JsxIdentifier.ts | 7 ++ src/ast/nodes/JsxOpeningElement.ts | 10 ++ src/ast/nodes/NodeType.ts | 4 + src/ast/nodes/index.ts | 4 + src/utils/bufferToAst.ts | 21 ++++ src/utils/parseAst.ts | 6 +- .../form/samples/jsx/preserves-jsx/_config.js | 4 +- .../samples/jsx/preserves-jsx/_expected.js | 7 +- 15 files changed, 256 insertions(+), 93 deletions(-) create mode 100644 src/ast/nodes/JsxIdentifier.ts create mode 100644 src/ast/nodes/JsxOpeningElement.ts diff --git a/rust/bindings_napi/src/lib.rs b/rust/bindings_napi/src/lib.rs index 58286e0e4b6..92e4cf9c1ba 100644 --- a/rust/bindings_napi/src/lib.rs +++ b/rust/bindings_napi/src/lib.rs @@ -21,7 +21,14 @@ impl Task for ParseTask { type JsValue = Buffer; fn compute(&mut self) -> Result { - Ok(parse_ast(self.code.clone(), self.allow_return_outside_function, self.jsx).into()) + Ok( + parse_ast( + self.code.clone(), + self.allow_return_outside_function, + self.jsx, + ) + .into(), + ) } fn resolve(&mut self, _env: Env, output: Self::Output) -> Result { diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 03bea2584a3..b03703236ba 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,11 +1,20 @@ use swc_common::Span; -use swc_ecma_ast::{AssignTarget, AssignTargetPat, CallExpr, Callee, ClassMember, Decl, ExportSpecifier, Expr, ExprOrSpread, ForHead, ImportSpecifier, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, JSXElement}; +use swc_ecma_ast::{ + AssignTarget, AssignTargetPat, CallExpr, Callee, ClassMember, Decl, ExportSpecifier, Expr, + ExprOrSpread, ForHead, ImportSpecifier, JSXElement, JSXElementName, JSXOpeningElement, Lit, + ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, + Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, +}; use crate::ast_nodes::call_expression::StoredCallee; use crate::ast_nodes::variable_declaration::VariableDeclaration; use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; use crate::convert_ast::converter::ast_constants::{ - TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, TYPE_FUNCTION_EXPRESSION, + JSX_ELEMENT_CHILDREN_OFFSET, JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, + JSX_IDENTIFIER_NAME_OFFSET, JSX_IDENTIFIER_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, + JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, TYPE_CLASS_EXPRESSION, + TYPE_FUNCTION_DECLARATION, TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ELEMENT, TYPE_JSX_IDENTIFIER, + TYPE_JSX_OPENING_ELEMENT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -359,7 +368,7 @@ impl<'a> AstConverter<'a> { Expr::JSXEmpty(_) => unimplemented!("Cannot convert Expr::JSXEmpty"), Expr::JSXElement(jsx_element) => { self.convert_jsx_element(jsx_element); - }, + } Expr::JSXFragment(_) => unimplemented!("Cannot convert Expr::JSXFragment"), Expr::TsTypeAssertion(_) => unimplemented!("Cannot convert Expr::TsTypeAssertion"), Expr::TsConstAssertion(_) => unimplemented!("Cannot convert Expr::TsConstAssertion"), @@ -653,23 +662,84 @@ impl<'a> AstConverter<'a> { } fn convert_jsx_element(&mut self, jsx_element: &JSXElement) { - panic!("JSXElement not supported"); - /* let end_position = self.add_type_and_start( - &TYPE_JSX_ELEMENT_EXPRESSION, - &jsx_element.span, - JSX_ELEMENT_EXPRESSION_RESERVED_BYTES, - false, - ); - self.store_identifier() - // argument - jsx_element.opening.as_ref().map(|expression| { - - - self.update_reference_position(end_position + YIELD_EXPRESSION_ARGUMENT_OFFSET); - self.convert_expression(expression) - }); - // end - self.add_end(end_position, &jsx_element.span);*/ + let end_position = self.add_type_and_start( + &TYPE_JSX_ELEMENT, + &jsx_element.span, + JSX_ELEMENT_RESERVED_BYTES, + false, + ); + // openingElement + self.update_reference_position(end_position + JSX_ELEMENT_OPENING_ELEMENT_OFFSET); + self.store_jsx_opening_element(&jsx_element.opening); + // children + self.convert_item_list( + &jsx_element.children, + end_position + JSX_ELEMENT_CHILDREN_OFFSET, + |ast_converter, jsx_element_child| { + // ast_converter.convert_jsx_element_child(jsx_element_child); + true + }, + ); + + // closingElement + // self.update_reference_position(end_position + JSX_ELEMENT_CLOSING_ELEMENT_OFFSET); + // self.store_jsx_closing() + + // end + self.add_end(end_position, &jsx_element.span); + } + + fn store_jsx_opening_element(&mut self, jsx_opening_element: &JSXOpeningElement) { + let end_position = self.add_type_and_start( + &TYPE_JSX_OPENING_ELEMENT, + &jsx_opening_element.span, + JSX_OPENING_ELEMENT_RESERVED_BYTES, + false, + ); + // name + self.update_reference_position(end_position + JSX_OPENING_ELEMENT_NAME_OFFSET); + self.store_jsx_element_name(&jsx_opening_element.name); + // attributes + self.convert_item_list( + &jsx_opening_element.attrs, + end_position + JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, + |ast_converter, jsx_attribute| { + unimplemented!("Convert JSXAttribute") + // ast_converter.store_jsx_attribute(jsx_attribute); + // true + }, + ); + // end + self.add_end(end_position, &jsx_opening_element.span); + } + + fn store_jsx_element_name(&mut self, jsx_element_name: &JSXElementName) { + let end_position = self.add_type_and_start( + &TYPE_JSX_IDENTIFIER, + match jsx_element_name { + JSXElementName::Ident(ident) => &ident.span, + JSXElementName::JSXMemberExpr(jsx_member_expr) => { + unimplemented!("JSXElementName::JSXMemberExpr") + } + JSXElementName::JSXNamespacedName(jsx_namespaced_name) => { + unimplemented!("JSXElementName::JSXNamespacedName") + } + }, + JSX_IDENTIFIER_RESERVED_BYTES, + false, + ); + + match jsx_element_name { + JSXElementName::Ident(ident) => { + self.convert_string(&ident.sym, end_position + JSX_IDENTIFIER_NAME_OFFSET); + } + JSXElementName::JSXMemberExpr(jsx_member_expr) => { + unimplemented!("JSXElementName::JSXMemberExpr") + } + JSXElementName::JSXNamespacedName(jsx_namespaced_name) => { + unimplemented!("JSXElementName::JSXNamespacedName") + } + } } } diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index 6e5b8c77d68..a309f264704 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -24,20 +24,23 @@ pub const TYPE_IDENTIFIER: [u8; 4] = 34u32.to_ne_bytes(); pub const TYPE_IMPORT_ATTRIBUTE: [u8; 4] = 36u32.to_ne_bytes(); pub const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); pub const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 51u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 52u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 53u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 54u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 58u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 59u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 60u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 61u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 64u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 71u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 74u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 77u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 78u32.to_ne_bytes(); +pub const TYPE_JSX_ELEMENT: [u8; 4] = 42u32.to_ne_bytes(); +pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 43u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 44u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 52u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 53u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 54u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 55u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 56u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 60u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 61u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 62u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 63u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 66u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 73u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 76u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 79u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 80u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -125,6 +128,18 @@ pub const IMPORT_EXPRESSION_RESERVED_BYTES: usize = 12; pub const IMPORT_EXPRESSION_SOURCE_OFFSET: usize = 4; pub const IMPORT_EXPRESSION_OPTIONS_OFFSET: usize = 8; +pub const JSX_ELEMENT_RESERVED_BYTES: usize = 16; +pub const JSX_ELEMENT_OPENING_ELEMENT_OFFSET: usize = 4; +pub const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 8; +pub const JSX_ELEMENT_CHILDREN_OFFSET: usize = 12; + +pub const JSX_IDENTIFIER_RESERVED_BYTES: usize = 8; +pub const JSX_IDENTIFIER_NAME_OFFSET: usize = 4; + +pub const JSX_OPENING_ELEMENT_RESERVED_BYTES: usize = 16; +pub const JSX_OPENING_ELEMENT_NAME_OFFSET: usize = 8; +pub const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; + pub const MEMBER_EXPRESSION_RESERVED_BYTES: usize = 16; pub const MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 8; pub const MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 12; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index ecd17d50c6e..97a1473adb8 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -315,38 +315,11 @@ macro_rules! store_import_specifier { }; } -#[macro_export] -macro_rules! store_jsx_element { - ($self:expr, span => $span:expr, openingElement => [$openingElement_value:expr, $openingElement_converter:ident], closingElement => [$closingElement_value:expr, $closingElement_converter:ident], children => [$children_value:expr, $children_converter:ident]) => { - let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&42u32.to_ne_bytes(), &$span, 16, false); - // openingElement - $self.update_reference_position(end_position + 4); - $self.$openingElement_converter(&$openingElement_value); - // closingElement - if let Some(value) = $closingElement_value.as_ref() { - $self.update_reference_position(end_position + 8); - $self.$closingElement_converter(value); - } - // children - $self.convert_item_list( - &$children_value, - end_position + 12, - |ast_converter, node| { - ast_converter.$children_converter(node); - true - }, - ); - // end - $self.add_end(end_position, &$span); - }; -} - #[macro_export] macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&43u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&45u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -362,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&44u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&46u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -377,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &45u32.to_ne_bytes(), + &47u32.to_ne_bytes(), &$span, 8, false, @@ -393,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&46u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&48u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -403,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&47u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&49u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -420,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&48u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&50u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -434,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&49u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&51u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -450,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -469,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -488,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -500,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&62u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&64u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -515,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&63u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -534,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -549,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -559,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -583,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&70u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -601,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -618,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &70u32.to_ne_bytes(), + &72u32.to_ne_bytes(), &$span, 16, false, @@ -640,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -650,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -663,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -680,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &76u32.to_ne_bytes(), + &78u32.to_ne_bytes(), &$span, 16, false, @@ -702,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -719,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &80u32.to_ne_bytes(), + &82u32.to_ne_bytes(), &$span, 12, false, @@ -801,6 +774,20 @@ macro_rules! store_function_declaration_flags { }; } +#[macro_export] +macro_rules! store_jsx_opening_element_flags { + ($self:expr, $end_position:expr, selfClosing => $selfClosing_value:expr) => { + let _: &mut AstConverter = $self; + let _: usize = $end_position; + let mut flags = 0u32; + if $selfClosing_value { + flags |= 1; + } + let flags_position = $end_position + 4; + $self.buffer[flags_position..flags_position + 4].copy_from_slice(&flags.to_ne_bytes()); + }; +} + #[macro_export] macro_rules! store_literal_boolean_flags { ($self:expr, $end_position:expr, value => $value_value:expr) => { diff --git a/scripts/ast-types.js b/scripts/ast-types.js index 946522976a7..7edc204da08 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -394,7 +394,22 @@ export const AST_NODES = { ['openingElement', 'Node'], ['closingElement', 'OptionalNode'], ['children', 'NodeList'] - ] + ], + useMacro: false + }, + JsxIdentifier: { + estreeType: 'any', + fields: [['name', 'String']], + useMacro: false + }, + JsxOpeningElement: { + estreeType: 'any', + fields: [ + ['name', 'Node'], + ['attributes', 'NodeList'] + ], + flags: ['selfClosing'], + useMacro: false }, LabeledStatement: { fields: [ diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index bafd883771d..a7bba1098ad 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -49,6 +49,8 @@ import ImportExpression from './nodes/ImportExpression'; import ImportNamespaceSpecifier from './nodes/ImportNamespaceSpecifier'; import ImportSpecifier from './nodes/ImportSpecifier'; import JsxElement from './nodes/JsxElement'; +import JsxIdentifier from './nodes/JsxIdentifier'; +import JsxOpeningElement from './nodes/JsxOpeningElement'; import LabeledStatement from './nodes/LabeledStatement'; import Literal from './nodes/Literal'; import LogicalExpression from './nodes/LogicalExpression'; @@ -143,6 +145,8 @@ const nodeTypeStrings = [ 'ImportNamespaceSpecifier', 'ImportSpecifier', 'JsxElement', + 'JsxIdentifier', + 'JsxOpeningElement', 'LabeledStatement', 'Literal', 'Literal', @@ -227,6 +231,8 @@ const nodeConstructors: (typeof NodeBase)[] = [ ImportNamespaceSpecifier, ImportSpecifier, JsxElement, + JsxIdentifier, + JsxOpeningElement, LabeledStatement, Literal, Literal, @@ -576,6 +582,16 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ : convertNode(node, scope, closingElementPosition, buffer); node.children = convertNodeList(node, scope, buffer[position + 2], buffer); }, + function jsxIdentifier(node: JsxIdentifier, position, buffer) { + node.name = buffer.convertString(buffer[position]); + }, + function jsxOpeningElement(node: JsxOpeningElement, position, buffer) { + const { scope } = node; + const flags = buffer[position]; + node.selfClosing = (flags & 1) === 1; + node.name = convertNode(node, scope, buffer[position + 1], buffer); + node.attributes = convertNodeList(node, scope, buffer[position + 2], buffer); + }, function labeledStatement(node: LabeledStatement, position, buffer) { const { scope } = node; node.label = convertNode(node, scope, buffer[position], buffer); diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index edec2767a55..8a7df2060be 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -42,6 +42,8 @@ export const childNodeKeys: Record = { ImportNamespaceSpecifier: ['local'], ImportSpecifier: ['imported', 'local'], JsxElement: ['openingElement', 'closingElement', 'children'], + JsxIdentifier: [], + JsxOpeningElement: ['name', 'attributes'], LabeledStatement: ['label', 'body'], Literal: [], LogicalExpression: ['left', 'right'], diff --git a/src/ast/nodes/JsxIdentifier.ts b/src/ast/nodes/JsxIdentifier.ts new file mode 100644 index 00000000000..839ab7e5b9e --- /dev/null +++ b/src/ast/nodes/JsxIdentifier.ts @@ -0,0 +1,7 @@ +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JsxIdentifier extends NodeBase { + type!: NodeType.tJsxIdentifier; + name!: string; +} diff --git a/src/ast/nodes/JsxOpeningElement.ts b/src/ast/nodes/JsxOpeningElement.ts new file mode 100644 index 00000000000..07b33940c56 --- /dev/null +++ b/src/ast/nodes/JsxOpeningElement.ts @@ -0,0 +1,10 @@ +import type JsxIdentifier from './JsxIdentifier'; +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JsxOpeningElement extends NodeBase { + type!: NodeType.tJsxOpeningElement; + selfClosing!: boolean; + name!: JsxIdentifier; + attributes!: any; // TODO JSXAttribute +} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index b83298b8329..a0a4ed603a2 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -41,6 +41,8 @@ export type tImportExpression = 'ImportExpression'; export type tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export type tImportSpecifier = 'ImportSpecifier'; export type tJsxElement = 'JsxElement'; +export type tJsxIdentifier = 'JsxIdentifier'; +export type tJsxOpeningElement = 'JsxOpeningElement'; export type tLabeledStatement = 'LabeledStatement'; export type tLiteral = 'Literal'; export type tLogicalExpression = 'LogicalExpression'; @@ -117,6 +119,8 @@ export const ImportExpression: tImportExpression = 'ImportExpression'; export const ImportNamespaceSpecifier: tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export const ImportSpecifier: tImportSpecifier = 'ImportSpecifier'; export const JsxElement: tJsxElement = 'JsxElement'; +export const JsxIdentifier: tJsxIdentifier = 'JsxIdentifier'; +export const JsxOpeningElement: tJsxOpeningElement = 'JsxOpeningElement'; export const LabeledStatement: tLabeledStatement = 'LabeledStatement'; export const Literal: tLiteral = 'Literal'; export const LogicalExpression: tLogicalExpression = 'LogicalExpression'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 92f57f1e7fb..c2896edef65 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -41,6 +41,8 @@ import ImportExpression from './ImportExpression'; import ImportNamespaceSpecifier from './ImportNamespaceSpecifier'; import ImportSpecifier from './ImportSpecifier'; import JsxElement from './JsxElement'; +import JsxIdentifier from './JsxIdentifier'; +import JsxOpeningElement from './JsxOpeningElement'; import LabeledStatement from './LabeledStatement'; import Literal from './Literal'; import LogicalExpression from './LogicalExpression'; @@ -120,6 +122,8 @@ export const nodeConstructors: Record = { ImportNamespaceSpecifier, ImportSpecifier, JsxElement, + JsxIdentifier, + JsxOpeningElement, LabeledStatement, Literal, LogicalExpression, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index 7d565532876..a95a81c6d2a 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -462,6 +462,25 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ children: convertNodeList(buffer[position + 4], buffer) }; }, + function jsxIdentifier(position, buffer): JsxIdentifierNode { + return { + type: 'JsxIdentifier', + start: buffer[position], + end: buffer[position + 1], + name: buffer.convertString(buffer[position + 2]) + }; + }, + function jsxOpeningElement(position, buffer): JsxOpeningElementNode { + const flags = buffer[position + 2]; + return { + type: 'JsxOpeningElement', + start: buffer[position], + end: buffer[position + 1], + selfClosing: (flags & 1) === 1, + name: convertNode(buffer[position + 3], buffer), + attributes: convertNodeList(buffer[position + 4], buffer) + }; + }, function labeledStatement(position, buffer): LabeledStatementNode { return { type: 'LabeledStatement', @@ -908,6 +927,8 @@ export type ImportExpressionNode = RollupAstNode< export type ImportNamespaceSpecifierNode = RollupAstNode; export type ImportSpecifierNode = RollupAstNode; export type JsxElementNode = RollupAstNode; +export type JsxIdentifierNode = RollupAstNode; +export type JsxOpeningElementNode = RollupAstNode; export type LabeledStatementNode = RollupAstNode; export type LiteralBigIntNode = RollupAstNode; export type LiteralBooleanNode = RollupAstNode; diff --git a/src/utils/parseAst.ts b/src/utils/parseAst.ts index 60ef163147d..4300ad847d3 100644 --- a/src/utils/parseAst.ts +++ b/src/utils/parseAst.ts @@ -3,8 +3,10 @@ import type { ParseAst, ParseAstAsync } from '../rollup/types'; import { convertProgram } from './bufferToAst'; import { getAstBuffer } from './getAstBuffer'; -export const parseAst: ParseAst = (input, { allowReturnOutsideFunction = false, jsx = false } = {}) => - convertProgram(getAstBuffer(parse(input, allowReturnOutsideFunction, jsx))); +export const parseAst: ParseAst = ( + input, + { allowReturnOutsideFunction = false, jsx = false } = {} +) => convertProgram(getAstBuffer(parse(input, allowReturnOutsideFunction, jsx))); export const parseAstAsync: ParseAstAsync = async ( input, diff --git a/test/form/samples/jsx/preserves-jsx/_config.js b/test/form/samples/jsx/preserves-jsx/_config.js index deba7dd3240..85f91019cc6 100644 --- a/test/form/samples/jsx/preserves-jsx/_config.js +++ b/test/form/samples/jsx/preserves-jsx/_config.js @@ -4,5 +4,7 @@ module.exports = defineTest({ options: { external: ['react'], jsx: 'preserve' - } + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], + verifyAst: false }); diff --git a/test/form/samples/jsx/preserves-jsx/_expected.js b/test/form/samples/jsx/preserves-jsx/_expected.js index 6dc07da2a1d..fb207c9ffcb 100644 --- a/test/form/samples/jsx/preserves-jsx/_expected.js +++ b/test/form/samples/jsx/preserves-jsx/_expected.js @@ -1,4 +1,5 @@ -import React from "react"; +import 'react'; -const Foo = () => {}; -export const result = ; +const result = ; + +export { result }; From 407fc32ca736d6c33c9b55ff1e8d2d628b2a7f6b Mon Sep 17 00:00:00 2001 From: Timo Peter Date: Sat, 2 Mar 2024 16:10:40 +0100 Subject: [PATCH 06/62] Add JSXElementChild -> JSXElement --- rust/parse_ast/src/convert_ast/converter.rs | 35 ++++++++++++++++--- .../jsx/preserves-jsx-child/_config.js | 10 ++++++ .../jsx/preserves-jsx-child/_expected.js | 5 +++ .../samples/jsx/preserves-jsx-child/main.js | 4 +++ .../jsx/preserves-jsx-closing/_config.js | 10 ++++++ .../jsx/preserves-jsx-closing/_expected.js | 5 +++ .../samples/jsx/preserves-jsx-closing/main.js | 4 +++ 7 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 test/form/samples/jsx/preserves-jsx-child/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-child/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-child/main.js create mode 100644 test/form/samples/jsx/preserves-jsx-closing/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-closing/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-closing/main.js diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index b03703236ba..6a8b5f846b0 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,9 +1,10 @@ use swc_common::Span; use swc_ecma_ast::{ - AssignTarget, AssignTargetPat, CallExpr, Callee, ClassMember, Decl, ExportSpecifier, Expr, - ExprOrSpread, ForHead, ImportSpecifier, JSXElement, JSXElementName, JSXOpeningElement, Lit, - ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, - Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, + AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, + ExprOrSpread, ForHead, ImportSpecifier, JSXElement, JSXElementChild, JSXElementName, + JSXOpeningElement, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, + OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, + VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; @@ -676,7 +677,7 @@ impl<'a> AstConverter<'a> { &jsx_element.children, end_position + JSX_ELEMENT_CHILDREN_OFFSET, |ast_converter, jsx_element_child| { - // ast_converter.convert_jsx_element_child(jsx_element_child); + ast_converter.convert_jsx_element_child(jsx_element_child); true }, ); @@ -689,6 +690,30 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &jsx_element.span); } + fn convert_jsx_element_child(&mut self, jsx_element_child: &JSXElementChild) { + match jsx_element_child { + JSXElementChild::JSXText(_jsx_text) => { + // self.store_jsx_text(jsx_text); + unimplemented!("JSXElementChild::JSXText") + } + JSXElementChild::JSXExprContainer(_jsx_expr_container) => { + // self.store_jsx_expr_container(jsx_expr_container); + unimplemented!("JSXElementChild::JSXExprContainer") + } + JSXElementChild::JSXSpreadChild(_jsx_spread_child) => { + // self.store_jsx_spread_child(jsx_spread_child); + unimplemented!("JSXElementChild::JSXSpreadChild") + } + JSXElementChild::JSXFragment(_jsx_fragment) => { + // self.store_jsx_fragment(jsx_fragment); + unimplemented!("JSXElementChild::JSXFragment") + } + JSXElementChild::JSXElement(jsx_element) => { + self.convert_jsx_element(jsx_element); + } + } + } + fn store_jsx_opening_element(&mut self, jsx_opening_element: &JSXOpeningElement) { let end_position = self.add_type_and_start( &TYPE_JSX_OPENING_ELEMENT, diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js new file mode 100644 index 00000000000..85f91019cc6 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX output', + options: { + external: ['react'], + jsx: 'preserve' + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], + verifyAst: false +}); diff --git a/test/form/samples/jsx/preserves-jsx-child/_expected.js b/test/form/samples/jsx/preserves-jsx-child/_expected.js new file mode 100644 index 00000000000..183372e19a6 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-child/_expected.js @@ -0,0 +1,5 @@ +import 'react'; + +const result = ; + +export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-child/main.js b/test/form/samples/jsx/preserves-jsx-child/main.js new file mode 100644 index 00000000000..6310739e2a4 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-child/main.js @@ -0,0 +1,4 @@ +import React from "react"; + +const Foo = () => {}; +export const result = ; diff --git a/test/form/samples/jsx/preserves-jsx-closing/_config.js b/test/form/samples/jsx/preserves-jsx-closing/_config.js new file mode 100644 index 00000000000..85f91019cc6 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-closing/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX output', + options: { + external: ['react'], + jsx: 'preserve' + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], + verifyAst: false +}); diff --git a/test/form/samples/jsx/preserves-jsx-closing/_expected.js b/test/form/samples/jsx/preserves-jsx-closing/_expected.js new file mode 100644 index 00000000000..90f20750cac --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-closing/_expected.js @@ -0,0 +1,5 @@ +import 'react'; + +const result = ; + +export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-closing/main.js b/test/form/samples/jsx/preserves-jsx-closing/main.js new file mode 100644 index 00000000000..f462943915c --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-closing/main.js @@ -0,0 +1,4 @@ +import React from "react"; + +const Foo = () => {}; +export const result = ; From 907fd9aa290f6cdf563bb47542b35a4dcf21d130 Mon Sep 17 00:00:00 2001 From: Timo Peter Date: Sat, 2 Mar 2024 16:32:16 +0100 Subject: [PATCH 07/62] Add JSXElementChild -> JSXText --- rust/parse_ast/src/convert_ast/converter.rs | 33 +++++++++---- .../convert_ast/converter/ast_constants.rs | 32 +++++++------ .../src/convert_ast/converter/ast_macros.rs | 48 +++++++++---------- scripts/ast-types.js | 5 ++ src/ast/bufferParsers.ts | 6 +++ src/ast/childNodeKeys.ts | 1 + src/ast/nodes/JsxText.ts | 7 +++ src/ast/nodes/NodeType.ts | 2 + src/ast/nodes/index.ts | 2 + src/utils/bufferToAst.ts | 9 ++++ .../samples/jsx/preserves-jsx-text/_config.js | 10 ++++ .../jsx/preserves-jsx-text/_expected.js | 5 ++ .../samples/jsx/preserves-jsx-text/main.js | 4 ++ 13 files changed, 116 insertions(+), 48 deletions(-) create mode 100644 src/ast/nodes/JsxText.ts create mode 100644 test/form/samples/jsx/preserves-jsx-text/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-text/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-text/main.js diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 6a8b5f846b0..df4b6e35a7f 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -2,9 +2,9 @@ use swc_common::Span; use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, ExprOrSpread, ForHead, ImportSpecifier, JSXElement, JSXElementChild, JSXElementName, - JSXOpeningElement, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, - OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, - VarDeclOrExpr, + JSXOpeningElement, JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, + ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, + Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; @@ -13,9 +13,10 @@ use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; use crate::convert_ast::converter::ast_constants::{ JSX_ELEMENT_CHILDREN_OFFSET, JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, JSX_IDENTIFIER_NAME_OFFSET, JSX_IDENTIFIER_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, - JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, TYPE_CLASS_EXPRESSION, - TYPE_FUNCTION_DECLARATION, TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ELEMENT, TYPE_JSX_IDENTIFIER, - TYPE_JSX_OPENING_ELEMENT, + JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, JSX_TEXT_RESERVED_BYTES, + JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, + TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ELEMENT, TYPE_JSX_IDENTIFIER, TYPE_JSX_OPENING_ELEMENT, + TYPE_JSX_TEXT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -436,7 +437,7 @@ impl<'a> AstConverter<'a> { Lit::Str(string_literal) => { self.store_literal_string(string_literal); } - Lit::JSXText(_) => unimplemented!("Lit::JSXText"), + Lit::JSXText(_) => unimplemented!("Lit::JsxText"), } } @@ -692,9 +693,8 @@ impl<'a> AstConverter<'a> { fn convert_jsx_element_child(&mut self, jsx_element_child: &JSXElementChild) { match jsx_element_child { - JSXElementChild::JSXText(_jsx_text) => { - // self.store_jsx_text(jsx_text); - unimplemented!("JSXElementChild::JSXText") + JSXElementChild::JSXText(jsx_text) => { + self.store_jsx_text(jsx_text); } JSXElementChild::JSXExprContainer(_jsx_expr_container) => { // self.store_jsx_expr_container(jsx_expr_container); @@ -714,6 +714,19 @@ impl<'a> AstConverter<'a> { } } + fn store_jsx_text(&mut self, jsx_text: &JSXText) { + let end_position = self.add_type_and_start( + &TYPE_JSX_TEXT, + &jsx_text.span, + JSX_TEXT_RESERVED_BYTES, + false, + ); + // value + self.convert_string(&jsx_text.value, end_position + JSX_TEXT_VALUE_OFFSET); + // end + self.add_end(end_position, &jsx_text.span); + } + fn store_jsx_opening_element(&mut self, jsx_opening_element: &JSXOpeningElement) { let end_position = self.add_type_and_start( &TYPE_JSX_OPENING_ELEMENT, diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index a309f264704..bb3f9895863 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -27,20 +27,21 @@ pub const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); pub const TYPE_JSX_ELEMENT: [u8; 4] = 42u32.to_ne_bytes(); pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 43u32.to_ne_bytes(); pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 44u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 52u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 53u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 54u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 55u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 56u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 60u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 61u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 62u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 63u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 66u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 73u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 76u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 79u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 80u32.to_ne_bytes(); +pub const TYPE_JSX_TEXT: [u8; 4] = 45u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 53u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 54u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 55u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 56u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 57u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 61u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 62u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 63u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 67u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 74u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 77u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 80u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 81u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -140,6 +141,9 @@ pub const JSX_OPENING_ELEMENT_RESERVED_BYTES: usize = 16; pub const JSX_OPENING_ELEMENT_NAME_OFFSET: usize = 8; pub const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; +pub const JSX_TEXT_RESERVED_BYTES: usize = 8; +pub const JSX_TEXT_VALUE_OFFSET: usize = 4; + pub const MEMBER_EXPRESSION_RESERVED_BYTES: usize = 16; pub const MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 8; pub const MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 12; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index 97a1473adb8..c154fb4c297 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -319,7 +319,7 @@ macro_rules! store_import_specifier { macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&45u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&46u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&46u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&47u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &47u32.to_ne_bytes(), + &48u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&48u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&49u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&49u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&50u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&50u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&51u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&51u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&52u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&64u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&70u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&70u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &72u32.to_ne_bytes(), + &73u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &78u32.to_ne_bytes(), + &79u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&82u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &82u32.to_ne_bytes(), + &83u32.to_ne_bytes(), &$span, 12, false, diff --git a/scripts/ast-types.js b/scripts/ast-types.js index 7edc204da08..f6fad68c2af 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -411,6 +411,11 @@ export const AST_NODES = { flags: ['selfClosing'], useMacro: false }, + JsxText: { + estreeType: 'any', + fields: [['value', 'String']], + useMacro: false + }, LabeledStatement: { fields: [ ['label', 'Node'], diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index a7bba1098ad..5dcc5e965ae 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -51,6 +51,7 @@ import ImportSpecifier from './nodes/ImportSpecifier'; import JsxElement from './nodes/JsxElement'; import JsxIdentifier from './nodes/JsxIdentifier'; import JsxOpeningElement from './nodes/JsxOpeningElement'; +import JsxText from './nodes/JsxText'; import LabeledStatement from './nodes/LabeledStatement'; import Literal from './nodes/Literal'; import LogicalExpression from './nodes/LogicalExpression'; @@ -147,6 +148,7 @@ const nodeTypeStrings = [ 'JsxElement', 'JsxIdentifier', 'JsxOpeningElement', + 'JsxText', 'LabeledStatement', 'Literal', 'Literal', @@ -233,6 +235,7 @@ const nodeConstructors: (typeof NodeBase)[] = [ JsxElement, JsxIdentifier, JsxOpeningElement, + JsxText, LabeledStatement, Literal, Literal, @@ -592,6 +595,9 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ node.name = convertNode(node, scope, buffer[position + 1], buffer); node.attributes = convertNodeList(node, scope, buffer[position + 2], buffer); }, + function jsxText(node: JsxText, position, buffer) { + node.value = buffer.convertString(buffer[position]); + }, function labeledStatement(node: LabeledStatement, position, buffer) { const { scope } = node; node.label = convertNode(node, scope, buffer[position], buffer); diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index 8a7df2060be..194e01e007a 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -44,6 +44,7 @@ export const childNodeKeys: Record = { JsxElement: ['openingElement', 'closingElement', 'children'], JsxIdentifier: [], JsxOpeningElement: ['name', 'attributes'], + JsxText: [], LabeledStatement: ['label', 'body'], Literal: [], LogicalExpression: ['left', 'right'], diff --git a/src/ast/nodes/JsxText.ts b/src/ast/nodes/JsxText.ts new file mode 100644 index 00000000000..a732022de96 --- /dev/null +++ b/src/ast/nodes/JsxText.ts @@ -0,0 +1,7 @@ +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JsxText extends NodeBase { + type!: NodeType.tJsxText; + value!: string; +} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index a0a4ed603a2..b635b3303d9 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -43,6 +43,7 @@ export type tImportSpecifier = 'ImportSpecifier'; export type tJsxElement = 'JsxElement'; export type tJsxIdentifier = 'JsxIdentifier'; export type tJsxOpeningElement = 'JsxOpeningElement'; +export type tJsxText = 'JsxText'; export type tLabeledStatement = 'LabeledStatement'; export type tLiteral = 'Literal'; export type tLogicalExpression = 'LogicalExpression'; @@ -121,6 +122,7 @@ export const ImportSpecifier: tImportSpecifier = 'ImportSpecifier'; export const JsxElement: tJsxElement = 'JsxElement'; export const JsxIdentifier: tJsxIdentifier = 'JsxIdentifier'; export const JsxOpeningElement: tJsxOpeningElement = 'JsxOpeningElement'; +export const JsxText: tJsxText = 'JsxText'; export const LabeledStatement: tLabeledStatement = 'LabeledStatement'; export const Literal: tLiteral = 'Literal'; export const LogicalExpression: tLogicalExpression = 'LogicalExpression'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index c2896edef65..5108df8ea87 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -43,6 +43,7 @@ import ImportSpecifier from './ImportSpecifier'; import JsxElement from './JsxElement'; import JsxIdentifier from './JsxIdentifier'; import JsxOpeningElement from './JsxOpeningElement'; +import JsxText from './JsxText'; import LabeledStatement from './LabeledStatement'; import Literal from './Literal'; import LogicalExpression from './LogicalExpression'; @@ -124,6 +125,7 @@ export const nodeConstructors: Record = { JsxElement, JsxIdentifier, JsxOpeningElement, + JsxText, LabeledStatement, Literal, LogicalExpression, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index a95a81c6d2a..0a3e7c60ff7 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -481,6 +481,14 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ attributes: convertNodeList(buffer[position + 4], buffer) }; }, + function jsxText(position, buffer): JsxTextNode { + return { + type: 'JsxText', + start: buffer[position], + end: buffer[position + 1], + value: buffer.convertString(buffer[position + 2]) + }; + }, function labeledStatement(position, buffer): LabeledStatementNode { return { type: 'LabeledStatement', @@ -929,6 +937,7 @@ export type ImportSpecifierNode = RollupAstNode; export type JsxElementNode = RollupAstNode; export type JsxIdentifierNode = RollupAstNode; export type JsxOpeningElementNode = RollupAstNode; +export type JsxTextNode = RollupAstNode; export type LabeledStatementNode = RollupAstNode; export type LiteralBigIntNode = RollupAstNode; export type LiteralBooleanNode = RollupAstNode; diff --git a/test/form/samples/jsx/preserves-jsx-text/_config.js b/test/form/samples/jsx/preserves-jsx-text/_config.js new file mode 100644 index 00000000000..85f91019cc6 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-text/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX output', + options: { + external: ['react'], + jsx: 'preserve' + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], + verifyAst: false +}); diff --git a/test/form/samples/jsx/preserves-jsx-text/_expected.js b/test/form/samples/jsx/preserves-jsx-text/_expected.js new file mode 100644 index 00000000000..d28dcc21e13 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-text/_expected.js @@ -0,0 +1,5 @@ +import 'react'; + +const result = some-text; + +export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-text/main.js b/test/form/samples/jsx/preserves-jsx-text/main.js new file mode 100644 index 00000000000..bb7a2e87cf3 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-text/main.js @@ -0,0 +1,4 @@ +import React from "react"; + +const Foo = () => {}; +export const result = some-text; From eb4648af318c1aa21aaa83399dd246b2dded62f4 Mon Sep 17 00:00:00 2001 From: Alexander Droll Date: Sat, 2 Mar 2024 17:08:30 +0100 Subject: [PATCH 08/62] WIP Add JsxAttribute --- rust/parse_ast/src/convert_ast/converter.rs | 106 +++++++++++++----- .../convert_ast/converter/ast_constants.rs | 40 ++++--- .../src/convert_ast/converter/ast_macros.rs | 48 ++++---- scripts/ast-types.js | 8 ++ src/ast/bufferParsers.ts | 7 ++ src/ast/childNodeKeys.ts | 1 + src/ast/nodes/JsxAttribute.ts | 9 ++ src/ast/nodes/NodeType.ts | 2 + src/ast/nodes/index.ts | 2 + src/utils/bufferToAst.ts | 9 ++ .../preserves-jsx-with-attributes/_config.js | 10 ++ .../_expected.js | 5 + .../jsx/preserves-jsx-with-attributes/main.js | 4 + 13 files changed, 179 insertions(+), 72 deletions(-) create mode 100644 src/ast/nodes/JsxAttribute.ts create mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/main.js diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index df4b6e35a7f..82416d6d297 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,22 +1,23 @@ use swc_common::Span; use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, - ExprOrSpread, ForHead, ImportSpecifier, JSXElement, JSXElementChild, JSXElementName, - JSXOpeningElement, JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, - ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, - Stmt, VarDeclOrExpr, + ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, + JSXElement, JSXElementChild, JSXElementName, JSXOpeningElement, JSXText, Lit, ModuleDecl, + ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, + PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; use crate::ast_nodes::variable_declaration::VariableDeclaration; use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; use crate::convert_ast::converter::ast_constants::{ - JSX_ELEMENT_CHILDREN_OFFSET, JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, - JSX_IDENTIFIER_NAME_OFFSET, JSX_IDENTIFIER_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, + JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_ELEMENT_CHILDREN_OFFSET, + JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, JSX_IDENTIFIER_NAME_OFFSET, + JSX_IDENTIFIER_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, - TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ELEMENT, TYPE_JSX_IDENTIFIER, TYPE_JSX_OPENING_ELEMENT, - TYPE_JSX_TEXT, + TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_ELEMENT, TYPE_JSX_IDENTIFIER, + TYPE_JSX_OPENING_ELEMENT, TYPE_JSX_TEXT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -24,6 +25,7 @@ use crate::convert_ast::converter::string_constants::{ use crate::convert_ast::converter::utf16_positions::{ ConvertedAnnotation, Utf8ToUtf16ByteIndexConverterAndAnnotationHandler, }; +use crate::store_jsx_opening_element_flags; pub(crate) mod analyze_code; pub mod string_constants; @@ -734,42 +736,32 @@ impl<'a> AstConverter<'a> { JSX_OPENING_ELEMENT_RESERVED_BYTES, false, ); + // flags + store_jsx_opening_element_flags!( + self, + end_position, + selfClosing => jsx_opening_element.self_closing + ); // name self.update_reference_position(end_position + JSX_OPENING_ELEMENT_NAME_OFFSET); - self.store_jsx_element_name(&jsx_opening_element.name); + self.convert_jsx_element_name(&jsx_opening_element.name); // attributes self.convert_item_list( &jsx_opening_element.attrs, end_position + JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, |ast_converter, jsx_attribute| { - unimplemented!("Convert JSXAttribute") - // ast_converter.store_jsx_attribute(jsx_attribute); - // true + ast_converter.convert_jsx_attribute_or_spread(jsx_attribute); + true }, ); // end self.add_end(end_position, &jsx_opening_element.span); } - fn store_jsx_element_name(&mut self, jsx_element_name: &JSXElementName) { - let end_position = self.add_type_and_start( - &TYPE_JSX_IDENTIFIER, - match jsx_element_name { - JSXElementName::Ident(ident) => &ident.span, - JSXElementName::JSXMemberExpr(jsx_member_expr) => { - unimplemented!("JSXElementName::JSXMemberExpr") - } - JSXElementName::JSXNamespacedName(jsx_namespaced_name) => { - unimplemented!("JSXElementName::JSXNamespacedName") - } - }, - JSX_IDENTIFIER_RESERVED_BYTES, - false, - ); - + fn convert_jsx_element_name(&mut self, jsx_element_name: &JSXElementName) { match jsx_element_name { - JSXElementName::Ident(ident) => { - self.convert_string(&ident.sym, end_position + JSX_IDENTIFIER_NAME_OFFSET); + JSXElementName::Ident(identifier) => { + self.store_jsx_identifier(&identifier.span, &identifier.sym) } JSXElementName::JSXMemberExpr(jsx_member_expr) => { unimplemented!("JSXElementName::JSXMemberExpr") @@ -779,6 +771,60 @@ impl<'a> AstConverter<'a> { } } } + + fn convert_jsx_attribute_or_spread(&mut self, jsx_attribute: &JSXAttrOrSpread) { + match jsx_attribute { + JSXAttrOrSpread::JSXAttr(jsx_attribute) => { + self.store_jsx_attribute(jsx_attribute); + } + JSXAttrOrSpread::SpreadElement(spread_element) => { + unimplemented!("JSXAttrOrSpread::SpreadElement") + } + } + } + + fn store_jsx_attribute(&mut self, jsx_attribute: &JSXAttr) { + let end_position = self.add_type_and_start( + &TYPE_JSX_ATTRIBUTE, + &jsx_attribute.span, + JSX_ATTRIBUTE_RESERVED_BYTES, + false, + ); + // name + self.update_reference_position(end_position + JSX_ATTRIBUTE_NAME_OFFSET); + self.convert_jsx_attribute_name(&jsx_attribute.name); + // value + // jsx_attribute.value.as_ref().map(|jsx_attribute_value| { + // self.update_reference_position(end_position + JSX_ATTRIBUTE_VALUE_OFFSET); + // self.store_jsx_attribute_value(jsx_attribute_value); + // }); + // end + self.add_end(end_position, &jsx_attribute.span); + } + + fn convert_jsx_attribute_name(&mut self, jsx_attribute_name: &JSXAttrName) { + match jsx_attribute_name { + JSXAttrName::Ident(identifier) => { + self.store_jsx_identifier(&identifier.span, &identifier.sym); + } + JSXAttrName::JSXNamespacedName(jsx_namespaced_name) => { + unimplemented!("JSXElementName::JSXNamespacedName") + } + } + } + + fn store_jsx_identifier(&mut self, span: &Span, name: &str) { + let end_position = self.add_type_and_start( + &TYPE_JSX_IDENTIFIER, + span, + JSX_IDENTIFIER_RESERVED_BYTES, + false, + ); + // name + self.convert_string(name, end_position + JSX_IDENTIFIER_NAME_OFFSET); + // end + self.add_end(end_position, span); + } } pub fn convert_annotation(buffer: &mut Vec, annotation: &ConvertedAnnotation) { diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index bb3f9895863..c6c463f4184 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -24,24 +24,25 @@ pub const TYPE_IDENTIFIER: [u8; 4] = 34u32.to_ne_bytes(); pub const TYPE_IMPORT_ATTRIBUTE: [u8; 4] = 36u32.to_ne_bytes(); pub const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); pub const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); -pub const TYPE_JSX_ELEMENT: [u8; 4] = 42u32.to_ne_bytes(); -pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 43u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 44u32.to_ne_bytes(); -pub const TYPE_JSX_TEXT: [u8; 4] = 45u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 53u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 54u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 55u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 56u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 57u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 61u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 62u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 63u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 64u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 67u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 74u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 77u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 80u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 81u32.to_ne_bytes(); +pub const TYPE_JSX_ATTRIBUTE: [u8; 4] = 42u32.to_ne_bytes(); +pub const TYPE_JSX_ELEMENT: [u8; 4] = 43u32.to_ne_bytes(); +pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 44u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 45u32.to_ne_bytes(); +pub const TYPE_JSX_TEXT: [u8; 4] = 46u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 54u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 55u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 56u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 57u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 58u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 62u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 63u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 65u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 68u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 75u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 78u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 81u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 82u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -129,6 +130,9 @@ pub const IMPORT_EXPRESSION_RESERVED_BYTES: usize = 12; pub const IMPORT_EXPRESSION_SOURCE_OFFSET: usize = 4; pub const IMPORT_EXPRESSION_OPTIONS_OFFSET: usize = 8; +pub const JSX_ATTRIBUTE_RESERVED_BYTES: usize = 8; +pub const JSX_ATTRIBUTE_NAME_OFFSET: usize = 4; + pub const JSX_ELEMENT_RESERVED_BYTES: usize = 16; pub const JSX_ELEMENT_OPENING_ELEMENT_OFFSET: usize = 4; pub const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 8; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index c154fb4c297..3c40202d2a1 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -319,7 +319,7 @@ macro_rules! store_import_specifier { macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&46u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&47u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&47u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&48u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &48u32.to_ne_bytes(), + &49u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&49u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&50u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&50u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&51u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&51u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&52u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&52u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&53u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&70u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&70u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &73u32.to_ne_bytes(), + &74u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &79u32.to_ne_bytes(), + &80u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&82u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&83u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &83u32.to_ne_bytes(), + &84u32.to_ne_bytes(), &$span, 12, false, diff --git a/scripts/ast-types.js b/scripts/ast-types.js index f6fad68c2af..83cd9af32fc 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -388,6 +388,14 @@ export const AST_NODES = { imported: 'local' } }, + JsxAttribute: { + estreeType: 'any', + fields: [ + ['name', 'Node'] + // ['value', 'OptionalString'] + ], + useMacro: false + }, JsxElement: { estreeType: 'any', fields: [ diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index 5dcc5e965ae..b221bb60cb4 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -48,6 +48,7 @@ import ImportDefaultSpecifier from './nodes/ImportDefaultSpecifier'; import ImportExpression from './nodes/ImportExpression'; import ImportNamespaceSpecifier from './nodes/ImportNamespaceSpecifier'; import ImportSpecifier from './nodes/ImportSpecifier'; +import JsxAttribute from './nodes/JsxAttribute'; import JsxElement from './nodes/JsxElement'; import JsxIdentifier from './nodes/JsxIdentifier'; import JsxOpeningElement from './nodes/JsxOpeningElement'; @@ -145,6 +146,7 @@ const nodeTypeStrings = [ 'ImportExpression', 'ImportNamespaceSpecifier', 'ImportSpecifier', + 'JsxAttribute', 'JsxElement', 'JsxIdentifier', 'JsxOpeningElement', @@ -232,6 +234,7 @@ const nodeConstructors: (typeof NodeBase)[] = [ ImportExpression, ImportNamespaceSpecifier, ImportSpecifier, + JsxAttribute, JsxElement, JsxIdentifier, JsxOpeningElement, @@ -575,6 +578,10 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ node.imported = importedPosition === 0 ? node.local : convertNode(node, scope, importedPosition, buffer); }, + function jsxAttribute(node: JsxAttribute, position, buffer) { + const { scope } = node; + node.name = convertNode(node, scope, buffer[position], buffer); + }, function jsxElement(node: JsxElement, position, buffer) { const { scope } = node; node.openingElement = convertNode(node, scope, buffer[position], buffer); diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index 194e01e007a..7923d4d9cab 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -41,6 +41,7 @@ export const childNodeKeys: Record = { ImportExpression: ['source', 'options'], ImportNamespaceSpecifier: ['local'], ImportSpecifier: ['imported', 'local'], + JsxAttribute: ['name'], JsxElement: ['openingElement', 'closingElement', 'children'], JsxIdentifier: [], JsxOpeningElement: ['name', 'attributes'], diff --git a/src/ast/nodes/JsxAttribute.ts b/src/ast/nodes/JsxAttribute.ts new file mode 100644 index 00000000000..70b23ac4897 --- /dev/null +++ b/src/ast/nodes/JsxAttribute.ts @@ -0,0 +1,9 @@ +import type JsxIdentifier from './JsxIdentifier'; +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JsxAttribute extends NodeBase { + declare name: JsxIdentifier; + declare value: undefined; + declare type: NodeType.tJsxAttribute; +} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index b635b3303d9..05b6ad37264 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -40,6 +40,7 @@ export type tImportDefaultSpecifier = 'ImportDefaultSpecifier'; export type tImportExpression = 'ImportExpression'; export type tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export type tImportSpecifier = 'ImportSpecifier'; +export type tJsxAttribute = 'JsxAttribute'; export type tJsxElement = 'JsxElement'; export type tJsxIdentifier = 'JsxIdentifier'; export type tJsxOpeningElement = 'JsxOpeningElement'; @@ -119,6 +120,7 @@ export const ImportDefaultSpecifier: tImportDefaultSpecifier = 'ImportDefaultSpe export const ImportExpression: tImportExpression = 'ImportExpression'; export const ImportNamespaceSpecifier: tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export const ImportSpecifier: tImportSpecifier = 'ImportSpecifier'; +export const JsxAttribute: tJsxAttribute = 'JsxAttribute'; export const JsxElement: tJsxElement = 'JsxElement'; export const JsxIdentifier: tJsxIdentifier = 'JsxIdentifier'; export const JsxOpeningElement: tJsxOpeningElement = 'JsxOpeningElement'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 5108df8ea87..d5feb8febae 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -40,6 +40,7 @@ import ImportDefaultSpecifier from './ImportDefaultSpecifier'; import ImportExpression from './ImportExpression'; import ImportNamespaceSpecifier from './ImportNamespaceSpecifier'; import ImportSpecifier from './ImportSpecifier'; +import JsxAttribute from './JsxAttribute'; import JsxElement from './JsxElement'; import JsxIdentifier from './JsxIdentifier'; import JsxOpeningElement from './JsxOpeningElement'; @@ -122,6 +123,7 @@ export const nodeConstructors: Record = { ImportExpression, ImportNamespaceSpecifier, ImportSpecifier, + JsxAttribute, JsxElement, JsxIdentifier, JsxOpeningElement, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index 0a3e7c60ff7..c1b32b58a52 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -450,6 +450,14 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ local }; }, + function jsxAttribute(position, buffer): JsxAttributeNode { + return { + type: 'JsxAttribute', + start: buffer[position], + end: buffer[position + 1], + name: convertNode(buffer[position + 2], buffer) + }; + }, function jsxElement(position, buffer): JsxElementNode { const closingElementPosition = buffer[position + 3]; return { @@ -934,6 +942,7 @@ export type ImportExpressionNode = RollupAstNode< >; export type ImportNamespaceSpecifierNode = RollupAstNode; export type ImportSpecifierNode = RollupAstNode; +export type JsxAttributeNode = RollupAstNode; export type JsxElementNode = RollupAstNode; export type JsxIdentifierNode = RollupAstNode; export type JsxOpeningElementNode = RollupAstNode; diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js b/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js new file mode 100644 index 00000000000..fc7469ffeed --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX with string attributes output', + options: { + external: ['react'], + jsx: 'preserve' + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], + verifyAst: false +}); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js b/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js new file mode 100644 index 00000000000..ae7bc58b591 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js @@ -0,0 +1,5 @@ +import 'react'; + +const result = ; + +export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/main.js b/test/form/samples/jsx/preserves-jsx-with-attributes/main.js new file mode 100644 index 00000000000..98af3100fbd --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/main.js @@ -0,0 +1,4 @@ +import React from 'react'; + +const Foo = () => {}; +export const result = ; From 2baff98e96e187754c05293d5060ff0b8c53177b Mon Sep 17 00:00:00 2001 From: Timo Peter Date: Sat, 2 Mar 2024 17:14:53 +0100 Subject: [PATCH 09/62] Add JSXElementChild -> JSXExprContainer and JSXEmptyExpr --- rust/parse_ast/src/convert_ast/converter.rs | 54 +++++++++++++++---- .../convert_ast/converter/ast_constants.rs | 41 ++++++++------ .../src/convert_ast/converter/ast_macros.rs | 48 ++++++++--------- scripts/ast-types.js | 9 ++++ src/ast/bufferParsers.ts | 11 ++++ src/ast/childNodeKeys.ts | 2 + src/ast/nodes/JsxEmptyExpr.ts | 6 +++ src/ast/nodes/JsxExprContainer.ts | 8 +++ src/ast/nodes/NodeType.ts | 4 ++ src/ast/nodes/index.ts | 4 ++ src/utils/bufferToAst.ts | 17 ++++++ .../preserves-jsx-empty-expression/_config.js | 10 ++++ .../_expected.js | 5 ++ .../preserves-jsx-empty-expression/main.js | 4 ++ .../_config.js | 10 ++++ .../_expected.js | 5 ++ .../main.js | 4 ++ 17 files changed, 190 insertions(+), 52 deletions(-) create mode 100644 src/ast/nodes/JsxEmptyExpr.ts create mode 100644 src/ast/nodes/JsxExprContainer.ts create mode 100644 test/form/samples/jsx/preserves-jsx-empty-expression/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-empty-expression/main.js create mode 100644 test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 82416d6d297..680842e2c5c 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,10 +1,10 @@ use swc_common::Span; use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, - ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, - JSXElement, JSXElementChild, JSXElementName, JSXOpeningElement, JSXText, Lit, ModuleDecl, - ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, - PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, + ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXElement, + JSXElementChild, JSXElementName, JSXEmptyExpr, JSXExpr, JSXExprContainer, JSXOpeningElement, + JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, + ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; @@ -12,12 +12,13 @@ use crate::ast_nodes::variable_declaration::VariableDeclaration; use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; use crate::convert_ast::converter::ast_constants::{ JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_ELEMENT_CHILDREN_OFFSET, - JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, JSX_IDENTIFIER_NAME_OFFSET, - JSX_IDENTIFIER_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, + JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, JSX_EMPTY_EXPR_RESERVED_BYTES, + JSX_EXPR_CONTAINER_EXPRESSION_OFFSET, JSX_EXPR_CONTAINER_RESERVED_BYTES, + JSX_IDENTIFIER_NAME_OFFSET, JSX_IDENTIFIER_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, - TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_ELEMENT, TYPE_JSX_IDENTIFIER, - TYPE_JSX_OPENING_ELEMENT, TYPE_JSX_TEXT, + TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_ELEMENT, TYPE_JSX_EMPTY_EXPR, + TYPE_JSX_EXPR_CONTAINER, TYPE_JSX_IDENTIFIER, TYPE_JSX_OPENING_ELEMENT, TYPE_JSX_TEXT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -698,9 +699,8 @@ impl<'a> AstConverter<'a> { JSXElementChild::JSXText(jsx_text) => { self.store_jsx_text(jsx_text); } - JSXElementChild::JSXExprContainer(_jsx_expr_container) => { - // self.store_jsx_expr_container(jsx_expr_container); - unimplemented!("JSXElementChild::JSXExprContainer") + JSXElementChild::JSXExprContainer(jsx_expr_container) => { + self.store_jsx_expr_container(jsx_expr_container); } JSXElementChild::JSXSpreadChild(_jsx_spread_child) => { // self.store_jsx_spread_child(jsx_spread_child); @@ -716,6 +716,38 @@ impl<'a> AstConverter<'a> { } } + fn store_jsx_expr_container(&mut self, jsx_expr_container: &JSXExprContainer) { + let end_position = self.add_type_and_start( + &TYPE_JSX_EXPR_CONTAINER, + &jsx_expr_container.span, + JSX_EXPR_CONTAINER_RESERVED_BYTES, + false, + ); + // expression + self.update_reference_position(end_position + JSX_EXPR_CONTAINER_EXPRESSION_OFFSET); + match &jsx_expr_container.expr { + JSXExpr::Expr(expression) => { + self.convert_expression(expression); + } + JSXExpr::JSXEmptyExpr(jsx_empty_expr) => { + self.store_jsx_empty_expr(jsx_empty_expr); + } + } + // end + self.add_end(end_position, &jsx_expr_container.span); + } + + fn store_jsx_empty_expr(&mut self, jsx_empty_expr: &JSXEmptyExpr) { + let end_position = self.add_type_and_start( + &TYPE_JSX_EMPTY_EXPR, + &jsx_empty_expr.span, + JSX_EMPTY_EXPR_RESERVED_BYTES, + false, + ); + // end + self.add_end(end_position, &jsx_empty_expr.span); + } + fn store_jsx_text(&mut self, jsx_text: &JSXText) { let end_position = self.add_type_and_start( &TYPE_JSX_TEXT, diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index c6c463f4184..f31ababd2e0 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -26,23 +26,25 @@ pub const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); pub const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); pub const TYPE_JSX_ATTRIBUTE: [u8; 4] = 42u32.to_ne_bytes(); pub const TYPE_JSX_ELEMENT: [u8; 4] = 43u32.to_ne_bytes(); -pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 44u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 45u32.to_ne_bytes(); -pub const TYPE_JSX_TEXT: [u8; 4] = 46u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 54u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 55u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 56u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 57u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 58u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 62u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 63u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 64u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 65u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 68u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 75u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 78u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 81u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 82u32.to_ne_bytes(); +pub const TYPE_JSX_EMPTY_EXPR: [u8; 4] = 44u32.to_ne_bytes(); +pub const TYPE_JSX_EXPR_CONTAINER: [u8; 4] = 45u32.to_ne_bytes(); +pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 46u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 47u32.to_ne_bytes(); +pub const TYPE_JSX_TEXT: [u8; 4] = 48u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 56u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 57u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 58u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 59u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 60u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 65u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 66u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 67u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 70u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 77u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 80u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 83u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 84u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -138,6 +140,11 @@ pub const JSX_ELEMENT_OPENING_ELEMENT_OFFSET: usize = 4; pub const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 8; pub const JSX_ELEMENT_CHILDREN_OFFSET: usize = 12; +pub const JSX_EMPTY_EXPR_RESERVED_BYTES: usize = 4; + +pub const JSX_EXPR_CONTAINER_RESERVED_BYTES: usize = 8; +pub const JSX_EXPR_CONTAINER_EXPRESSION_OFFSET: usize = 4; + pub const JSX_IDENTIFIER_RESERVED_BYTES: usize = 8; pub const JSX_IDENTIFIER_NAME_OFFSET: usize = 4; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index 3c40202d2a1..481b43ca588 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -319,7 +319,7 @@ macro_rules! store_import_specifier { macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&47u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&49u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&48u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&50u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &49u32.to_ne_bytes(), + &51u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&50u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&52u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&51u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&53u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&52u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&54u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&53u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&62u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&63u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&70u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &74u32.to_ne_bytes(), + &76u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &80u32.to_ne_bytes(), + &82u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&83u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&85u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &84u32.to_ne_bytes(), + &86u32.to_ne_bytes(), &$span, 12, false, diff --git a/scripts/ast-types.js b/scripts/ast-types.js index 83cd9af32fc..3edf9483d99 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -405,6 +405,15 @@ export const AST_NODES = { ], useMacro: false }, + JsxEmptyExpr: { + estreeType: 'any', + useMacro: false + }, + JsxExprContainer: { + estreeType: 'any', + fields: [['expression', 'Node']], + useMacro: false + }, JsxIdentifier: { estreeType: 'any', fields: [['name', 'String']], diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index b221bb60cb4..92a4ce7f156 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -50,6 +50,8 @@ import ImportNamespaceSpecifier from './nodes/ImportNamespaceSpecifier'; import ImportSpecifier from './nodes/ImportSpecifier'; import JsxAttribute from './nodes/JsxAttribute'; import JsxElement from './nodes/JsxElement'; +import JsxEmptyExpr from './nodes/JsxEmptyExpr'; +import JsxExprContainer from './nodes/JsxExprContainer'; import JsxIdentifier from './nodes/JsxIdentifier'; import JsxOpeningElement from './nodes/JsxOpeningElement'; import JsxText from './nodes/JsxText'; @@ -148,6 +150,8 @@ const nodeTypeStrings = [ 'ImportSpecifier', 'JsxAttribute', 'JsxElement', + 'JsxEmptyExpr', + 'JsxExprContainer', 'JsxIdentifier', 'JsxOpeningElement', 'JsxText', @@ -236,6 +240,8 @@ const nodeConstructors: (typeof NodeBase)[] = [ ImportSpecifier, JsxAttribute, JsxElement, + JsxEmptyExpr, + JsxExprContainer, JsxIdentifier, JsxOpeningElement, JsxText, @@ -592,6 +598,11 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ : convertNode(node, scope, closingElementPosition, buffer); node.children = convertNodeList(node, scope, buffer[position + 2], buffer); }, + function jsxEmptyExpr() {}, + function jsxExprContainer(node: JsxExprContainer, position, buffer) { + const { scope } = node; + node.expression = convertNode(node, scope, buffer[position], buffer); + }, function jsxIdentifier(node: JsxIdentifier, position, buffer) { node.name = buffer.convertString(buffer[position]); }, diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index 7923d4d9cab..651cfd98549 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -43,6 +43,8 @@ export const childNodeKeys: Record = { ImportSpecifier: ['imported', 'local'], JsxAttribute: ['name'], JsxElement: ['openingElement', 'closingElement', 'children'], + JsxEmptyExpr: [], + JsxExprContainer: ['expression'], JsxIdentifier: [], JsxOpeningElement: ['name', 'attributes'], JsxText: [], diff --git a/src/ast/nodes/JsxEmptyExpr.ts b/src/ast/nodes/JsxEmptyExpr.ts new file mode 100644 index 00000000000..a19c10eb633 --- /dev/null +++ b/src/ast/nodes/JsxEmptyExpr.ts @@ -0,0 +1,6 @@ +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JsxEmptyExpr extends NodeBase { + type!: NodeType.tJsxEmptyExpr; +} diff --git a/src/ast/nodes/JsxExprContainer.ts b/src/ast/nodes/JsxExprContainer.ts new file mode 100644 index 00000000000..d25a83a8969 --- /dev/null +++ b/src/ast/nodes/JsxExprContainer.ts @@ -0,0 +1,8 @@ +import type * as NodeType from './NodeType'; +import type { ExpressionNode } from './shared/Node'; +import { NodeBase } from './shared/Node'; + +export default class JsxExprContainer extends NodeBase { + type!: NodeType.tJsxExprContainer; + expression!: ExpressionNode; +} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index 05b6ad37264..4da2c664417 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -42,6 +42,8 @@ export type tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export type tImportSpecifier = 'ImportSpecifier'; export type tJsxAttribute = 'JsxAttribute'; export type tJsxElement = 'JsxElement'; +export type tJsxEmptyExpr = 'JsxEmptyExpr'; +export type tJsxExprContainer = 'JsxExprContainer'; export type tJsxIdentifier = 'JsxIdentifier'; export type tJsxOpeningElement = 'JsxOpeningElement'; export type tJsxText = 'JsxText'; @@ -122,6 +124,8 @@ export const ImportNamespaceSpecifier: tImportNamespaceSpecifier = 'ImportNamesp export const ImportSpecifier: tImportSpecifier = 'ImportSpecifier'; export const JsxAttribute: tJsxAttribute = 'JsxAttribute'; export const JsxElement: tJsxElement = 'JsxElement'; +export const JsxEmptyExpr: tJsxEmptyExpr = 'JsxEmptyExpr'; +export const JsxExprContainer: tJsxExprContainer = 'JsxExprContainer'; export const JsxIdentifier: tJsxIdentifier = 'JsxIdentifier'; export const JsxOpeningElement: tJsxOpeningElement = 'JsxOpeningElement'; export const JsxText: tJsxText = 'JsxText'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index d5feb8febae..4757f0d7773 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -42,6 +42,8 @@ import ImportNamespaceSpecifier from './ImportNamespaceSpecifier'; import ImportSpecifier from './ImportSpecifier'; import JsxAttribute from './JsxAttribute'; import JsxElement from './JsxElement'; +import JsxEmptyExpr from './JsxEmptyExpr'; +import JsxExprContainer from './JsxExprContainer'; import JsxIdentifier from './JsxIdentifier'; import JsxOpeningElement from './JsxOpeningElement'; import JsxText from './JsxText'; @@ -125,6 +127,8 @@ export const nodeConstructors: Record = { ImportSpecifier, JsxAttribute, JsxElement, + JsxEmptyExpr, + JsxExprContainer, JsxIdentifier, JsxOpeningElement, JsxText, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index c1b32b58a52..22f5210dc75 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -470,6 +470,21 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ children: convertNodeList(buffer[position + 4], buffer) }; }, + function jsxEmptyExpr(position, buffer): JsxEmptyExprNode { + return { + type: 'JsxEmptyExpr', + start: buffer[position], + end: buffer[position + 1] + }; + }, + function jsxExprContainer(position, buffer): JsxExprContainerNode { + return { + type: 'JsxExprContainer', + start: buffer[position], + end: buffer[position + 1], + expression: convertNode(buffer[position + 2], buffer) + }; + }, function jsxIdentifier(position, buffer): JsxIdentifierNode { return { type: 'JsxIdentifier', @@ -944,6 +959,8 @@ export type ImportNamespaceSpecifierNode = RollupAstNode; export type JsxAttributeNode = RollupAstNode; export type JsxElementNode = RollupAstNode; +export type JsxEmptyExprNode = RollupAstNode; +export type JsxExprContainerNode = RollupAstNode; export type JsxIdentifierNode = RollupAstNode; export type JsxOpeningElementNode = RollupAstNode; export type JsxTextNode = RollupAstNode; diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js new file mode 100644 index 00000000000..85f91019cc6 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX output', + options: { + external: ['react'], + jsx: 'preserve' + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], + verifyAst: false +}); diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js new file mode 100644 index 00000000000..8c81c0b0c7a --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js @@ -0,0 +1,5 @@ +import 'react'; + +const result = {}; + +export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/main.js b/test/form/samples/jsx/preserves-jsx-empty-expression/main.js new file mode 100644 index 00000000000..90c47f081b4 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/main.js @@ -0,0 +1,4 @@ +import React from 'react'; + +const Foo = () => {}; +export const result = {}; diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js new file mode 100644 index 00000000000..85f91019cc6 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX output', + options: { + external: ['react'], + jsx: 'preserve' + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], + verifyAst: false +}); diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js new file mode 100644 index 00000000000..380d04d0873 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js @@ -0,0 +1,5 @@ +import 'react'; + +const result = {'test'}; + +export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js new file mode 100644 index 00000000000..2122023f0d9 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js @@ -0,0 +1,4 @@ +import React from 'react'; + +const Foo = () => {}; +export const result = {'test'}; From 66ae8fdc1087e97b4da3635cfb53264d587fc5fc Mon Sep 17 00:00:00 2001 From: Felix Huttmann Date: Sat, 2 Mar 2024 17:49:06 +0100 Subject: [PATCH 10/62] Add JsxFragment --- rust/parse_ast/src/convert_ast/converter.rs | 85 +++++++++++++++---- .../convert_ast/converter/ast_constants.rs | 52 +++++++----- .../src/convert_ast/converter/ast_macros.rs | 48 +++++------ scripts/ast-types.js | 19 +++++ src/ast/bufferParsers.ts | 17 ++++ src/ast/childNodeKeys.ts | 3 + src/ast/nodes/JsxClosingFragment.ts | 6 ++ src/ast/nodes/JsxFragment.ts | 9 ++ src/ast/nodes/JsxOpeningFragment.ts | 7 ++ src/ast/nodes/NodeType.ts | 6 ++ src/ast/nodes/index.ts | 6 ++ src/utils/bufferToAst.ts | 27 ++++++ .../jsx/preserves-jsx-fragment/_config.js | 10 +++ .../jsx/preserves-jsx-fragment/_expected.js | 5 ++ .../jsx/preserves-jsx-fragment/main.js | 4 + 15 files changed, 245 insertions(+), 59 deletions(-) create mode 100644 src/ast/nodes/JsxClosingFragment.ts create mode 100644 src/ast/nodes/JsxFragment.ts create mode 100644 src/ast/nodes/JsxOpeningFragment.ts create mode 100644 test/form/samples/jsx/preserves-jsx-fragment/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-fragment/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-fragment/main.js diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 680842e2c5c..7f3eaefe8af 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,24 +1,29 @@ use swc_common::Span; use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, - ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXElement, - JSXElementChild, JSXElementName, JSXEmptyExpr, JSXExpr, JSXExprContainer, JSXOpeningElement, - JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, - ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, + ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, + JSXClosingFragment, JSXElement, JSXElementChild, JSXElementName, JSXEmptyExpr, JSXExpr, + JSXExprContainer, JSXFragment, JSXOpeningElement, JSXOpeningFragment, JSXText, Lit, ModuleDecl, + ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, + PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; use crate::ast_nodes::variable_declaration::VariableDeclaration; use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; use crate::convert_ast::converter::ast_constants::{ - JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_ELEMENT_CHILDREN_OFFSET, - JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, JSX_EMPTY_EXPR_RESERVED_BYTES, - JSX_EXPR_CONTAINER_EXPRESSION_OFFSET, JSX_EXPR_CONTAINER_RESERVED_BYTES, - JSX_IDENTIFIER_NAME_OFFSET, JSX_IDENTIFIER_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, - JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, JSX_TEXT_RESERVED_BYTES, + JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_CLOSING_FRAGMENT_RESERVED_BYTES, + JSX_ELEMENT_CHILDREN_OFFSET, JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, + JSX_EMPTY_EXPR_RESERVED_BYTES, JSX_EXPR_CONTAINER_EXPRESSION_OFFSET, + JSX_EXPR_CONTAINER_RESERVED_BYTES, JSX_FRAGMENT_CHILDREN_OFFSET, + JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET, JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET, + JSX_FRAGMENT_RESERVED_BYTES, JSX_IDENTIFIER_NAME_OFFSET, JSX_IDENTIFIER_RESERVED_BYTES, + JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, + JSX_OPENING_ELEMENT_RESERVED_BYTES, JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, - TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_ELEMENT, TYPE_JSX_EMPTY_EXPR, - TYPE_JSX_EXPR_CONTAINER, TYPE_JSX_IDENTIFIER, TYPE_JSX_OPENING_ELEMENT, TYPE_JSX_TEXT, + TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_CLOSING_FRAGMENT, TYPE_JSX_ELEMENT, + TYPE_JSX_EMPTY_EXPR, TYPE_JSX_EXPR_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, + TYPE_JSX_OPENING_ELEMENT, TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_TEXT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -374,7 +379,9 @@ impl<'a> AstConverter<'a> { Expr::JSXElement(jsx_element) => { self.convert_jsx_element(jsx_element); } - Expr::JSXFragment(_) => unimplemented!("Cannot convert Expr::JSXFragment"), + Expr::JSXFragment(jsx_fragment) => { + self.convert_jsx_fragment(jsx_fragment); + } Expr::TsTypeAssertion(_) => unimplemented!("Cannot convert Expr::TsTypeAssertion"), Expr::TsConstAssertion(_) => unimplemented!("Cannot convert Expr::TsConstAssertion"), Expr::TsNonNull(_) => unimplemented!("Cannot convert Expr::TsNonNull"), @@ -706,9 +713,8 @@ impl<'a> AstConverter<'a> { // self.store_jsx_spread_child(jsx_spread_child); unimplemented!("JSXElementChild::JSXSpreadChild") } - JSXElementChild::JSXFragment(_jsx_fragment) => { - // self.store_jsx_fragment(jsx_fragment); - unimplemented!("JSXElementChild::JSXFragment") + JSXElementChild::JSXFragment(jsx_fragment) => { + self.convert_jsx_fragment(jsx_fragment); } JSXElementChild::JSXElement(jsx_element) => { self.convert_jsx_element(jsx_element); @@ -857,6 +863,55 @@ impl<'a> AstConverter<'a> { // end self.add_end(end_position, span); } + + fn convert_jsx_fragment(&mut self, jsx_fragment: &JSXFragment) { + let end_position = self.add_type_and_start( + &TYPE_JSX_FRAGMENT, + &jsx_fragment.span, + JSX_FRAGMENT_RESERVED_BYTES, + false, + ); + // openingFragment + self.update_reference_position(end_position + JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET); + self.store_jsx_opening_fragment(jsx_fragment.opening); + // children + self.convert_item_list( + &jsx_fragment.children, + end_position + JSX_FRAGMENT_CHILDREN_OFFSET, + |ast_converter, jsx_fragment_child| { + unimplemented!("Convert JSXFragmentChild"); + // ast_converter.convert_jsx_fragment_child(jsx_fragment_child); + // true + }, + ); + // closingFragment + self.update_reference_position(end_position + JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET); + self.store_jsx_closing_fragment(&jsx_fragment.closing); + // end + self.add_end(end_position, &jsx_fragment.span); + } + + fn store_jsx_opening_fragment(&mut self, jsxopening_fragment: JSXOpeningFragment) { + let end_position = self.add_type_and_start( + &TYPE_JSX_OPENING_FRAGMENT, + &jsxopening_fragment.span, + JSX_OPENING_FRAGMENT_RESERVED_BYTES, + false, + ); + // end + self.add_end(end_position, &jsxopening_fragment.span); + } + + fn store_jsx_closing_fragment(&mut self, jsx_closing_fragment: &JSXClosingFragment) { + let end_position = self.add_type_and_start( + &TYPE_JSX_CLOSING_FRAGMENT, + &jsx_closing_fragment.span, + JSX_CLOSING_FRAGMENT_RESERVED_BYTES, + false, + ); + // end + self.add_end(end_position, &jsx_closing_fragment.span); + } } pub fn convert_annotation(buffer: &mut Vec, annotation: &ConvertedAnnotation) { diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index f31ababd2e0..172277bf0af 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -25,26 +25,29 @@ pub const TYPE_IMPORT_ATTRIBUTE: [u8; 4] = 36u32.to_ne_bytes(); pub const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); pub const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); pub const TYPE_JSX_ATTRIBUTE: [u8; 4] = 42u32.to_ne_bytes(); -pub const TYPE_JSX_ELEMENT: [u8; 4] = 43u32.to_ne_bytes(); -pub const TYPE_JSX_EMPTY_EXPR: [u8; 4] = 44u32.to_ne_bytes(); -pub const TYPE_JSX_EXPR_CONTAINER: [u8; 4] = 45u32.to_ne_bytes(); -pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 46u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 47u32.to_ne_bytes(); -pub const TYPE_JSX_TEXT: [u8; 4] = 48u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 56u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 57u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 58u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 59u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 60u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 64u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 65u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 66u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 67u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 70u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 77u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 80u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 83u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 84u32.to_ne_bytes(); +pub const TYPE_JSX_CLOSING_FRAGMENT: [u8; 4] = 43u32.to_ne_bytes(); +pub const TYPE_JSX_ELEMENT: [u8; 4] = 44u32.to_ne_bytes(); +pub const TYPE_JSX_EMPTY_EXPR: [u8; 4] = 45u32.to_ne_bytes(); +pub const TYPE_JSX_EXPR_CONTAINER: [u8; 4] = 46u32.to_ne_bytes(); +pub const TYPE_JSX_FRAGMENT: [u8; 4] = 47u32.to_ne_bytes(); +pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 48u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 49u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 50u32.to_ne_bytes(); +pub const TYPE_JSX_TEXT: [u8; 4] = 51u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 59u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 60u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 61u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 62u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 63u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 67u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 68u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 69u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 70u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 73u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 80u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 83u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 86u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 87u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -135,6 +138,8 @@ pub const IMPORT_EXPRESSION_OPTIONS_OFFSET: usize = 8; pub const JSX_ATTRIBUTE_RESERVED_BYTES: usize = 8; pub const JSX_ATTRIBUTE_NAME_OFFSET: usize = 4; +pub const JSX_CLOSING_FRAGMENT_RESERVED_BYTES: usize = 4; + pub const JSX_ELEMENT_RESERVED_BYTES: usize = 16; pub const JSX_ELEMENT_OPENING_ELEMENT_OFFSET: usize = 4; pub const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 8; @@ -145,6 +150,11 @@ pub const JSX_EMPTY_EXPR_RESERVED_BYTES: usize = 4; pub const JSX_EXPR_CONTAINER_RESERVED_BYTES: usize = 8; pub const JSX_EXPR_CONTAINER_EXPRESSION_OFFSET: usize = 4; +pub const JSX_FRAGMENT_RESERVED_BYTES: usize = 16; +pub const JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET: usize = 4; +pub const JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET: usize = 8; +pub const JSX_FRAGMENT_CHILDREN_OFFSET: usize = 12; + pub const JSX_IDENTIFIER_RESERVED_BYTES: usize = 8; pub const JSX_IDENTIFIER_NAME_OFFSET: usize = 4; @@ -152,6 +162,8 @@ pub const JSX_OPENING_ELEMENT_RESERVED_BYTES: usize = 16; pub const JSX_OPENING_ELEMENT_NAME_OFFSET: usize = 8; pub const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; +pub const JSX_OPENING_FRAGMENT_RESERVED_BYTES: usize = 4; + pub const JSX_TEXT_RESERVED_BYTES: usize = 8; pub const JSX_TEXT_VALUE_OFFSET: usize = 4; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index 481b43ca588..806c9c5d386 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -319,7 +319,7 @@ macro_rules! store_import_specifier { macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&49u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&52u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&50u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&53u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &51u32.to_ne_bytes(), + &54u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&52u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&53u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&54u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&64u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&62u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&63u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &76u32.to_ne_bytes(), + &79u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&82u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&84u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &82u32.to_ne_bytes(), + &85u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&85u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&88u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &86u32.to_ne_bytes(), + &89u32.to_ne_bytes(), &$span, 12, false, diff --git a/scripts/ast-types.js b/scripts/ast-types.js index 3edf9483d99..556b2db2567 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -396,6 +396,11 @@ export const AST_NODES = { ], useMacro: false }, + JsxClosingFragment: { + estreeType: 'any', + fields: [], + useMacro: false + }, JsxElement: { estreeType: 'any', fields: [ @@ -414,6 +419,15 @@ export const AST_NODES = { fields: [['expression', 'Node']], useMacro: false }, + JsxFragment: { + estreeType: 'any', + fields: [ + ['openingFragment', 'Node'], + ['closingFragment', 'Node'], + ['children', 'NodeList'] + ], + useMacro: false + }, JsxIdentifier: { estreeType: 'any', fields: [['name', 'String']], @@ -428,6 +442,11 @@ export const AST_NODES = { flags: ['selfClosing'], useMacro: false }, + JsxOpeningFragment: { + estreeType: 'any', + fields: [], + useMacro: false + }, JsxText: { estreeType: 'any', fields: [['value', 'String']], diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index 92a4ce7f156..1bf747ae257 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -49,11 +49,14 @@ import ImportExpression from './nodes/ImportExpression'; import ImportNamespaceSpecifier from './nodes/ImportNamespaceSpecifier'; import ImportSpecifier from './nodes/ImportSpecifier'; import JsxAttribute from './nodes/JsxAttribute'; +import JsxClosingFragment from './nodes/JsxClosingFragment'; import JsxElement from './nodes/JsxElement'; import JsxEmptyExpr from './nodes/JsxEmptyExpr'; import JsxExprContainer from './nodes/JsxExprContainer'; +import JsxFragment from './nodes/JsxFragment'; import JsxIdentifier from './nodes/JsxIdentifier'; import JsxOpeningElement from './nodes/JsxOpeningElement'; +import JsxOpeningFragment from './nodes/JsxOpeningFragment'; import JsxText from './nodes/JsxText'; import LabeledStatement from './nodes/LabeledStatement'; import Literal from './nodes/Literal'; @@ -149,11 +152,14 @@ const nodeTypeStrings = [ 'ImportNamespaceSpecifier', 'ImportSpecifier', 'JsxAttribute', + 'JsxClosingFragment', 'JsxElement', 'JsxEmptyExpr', 'JsxExprContainer', + 'JsxFragment', 'JsxIdentifier', 'JsxOpeningElement', + 'JsxOpeningFragment', 'JsxText', 'LabeledStatement', 'Literal', @@ -239,11 +245,14 @@ const nodeConstructors: (typeof NodeBase)[] = [ ImportNamespaceSpecifier, ImportSpecifier, JsxAttribute, + JsxClosingFragment, JsxElement, JsxEmptyExpr, JsxExprContainer, + JsxFragment, JsxIdentifier, JsxOpeningElement, + JsxOpeningFragment, JsxText, LabeledStatement, Literal, @@ -588,6 +597,7 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ const { scope } = node; node.name = convertNode(node, scope, buffer[position], buffer); }, + function jsxClosingFragment() {}, function jsxElement(node: JsxElement, position, buffer) { const { scope } = node; node.openingElement = convertNode(node, scope, buffer[position], buffer); @@ -603,6 +613,12 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ const { scope } = node; node.expression = convertNode(node, scope, buffer[position], buffer); }, + function jsxFragment(node: JsxFragment, position, buffer) { + const { scope } = node; + node.openingFragment = convertNode(node, scope, buffer[position], buffer); + node.closingFragment = convertNode(node, scope, buffer[position + 1], buffer); + node.children = convertNodeList(node, scope, buffer[position + 2], buffer); + }, function jsxIdentifier(node: JsxIdentifier, position, buffer) { node.name = buffer.convertString(buffer[position]); }, @@ -613,6 +629,7 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ node.name = convertNode(node, scope, buffer[position + 1], buffer); node.attributes = convertNodeList(node, scope, buffer[position + 2], buffer); }, + function jsxOpeningFragment() {}, function jsxText(node: JsxText, position, buffer) { node.value = buffer.convertString(buffer[position]); }, diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index 651cfd98549..95df38b54d2 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -42,11 +42,14 @@ export const childNodeKeys: Record = { ImportNamespaceSpecifier: ['local'], ImportSpecifier: ['imported', 'local'], JsxAttribute: ['name'], + JsxClosingFragment: [], JsxElement: ['openingElement', 'closingElement', 'children'], JsxEmptyExpr: [], JsxExprContainer: ['expression'], + JsxFragment: ['openingFragment', 'closingFragment', 'children'], JsxIdentifier: [], JsxOpeningElement: ['name', 'attributes'], + JsxOpeningFragment: [], JsxText: [], LabeledStatement: ['label', 'body'], Literal: [], diff --git a/src/ast/nodes/JsxClosingFragment.ts b/src/ast/nodes/JsxClosingFragment.ts new file mode 100644 index 00000000000..60c1c3e0d01 --- /dev/null +++ b/src/ast/nodes/JsxClosingFragment.ts @@ -0,0 +1,6 @@ +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JsxClosingFragment extends NodeBase { + declare type: NodeType.tJsxElement; +} diff --git a/src/ast/nodes/JsxFragment.ts b/src/ast/nodes/JsxFragment.ts new file mode 100644 index 00000000000..4cc9a2a8719 --- /dev/null +++ b/src/ast/nodes/JsxFragment.ts @@ -0,0 +1,9 @@ +import type * as NodeType from './NodeType'; +import { type ExpressionNode, NodeBase } from './shared/Node'; + +export default class JsxElement extends NodeBase { + declare closingFragment: unknown; + declare openingFragment: unknown; + declare type: NodeType.tJsxElement; + declare children: ExpressionNode[]; +} diff --git a/src/ast/nodes/JsxOpeningFragment.ts b/src/ast/nodes/JsxOpeningFragment.ts new file mode 100644 index 00000000000..72a0199778b --- /dev/null +++ b/src/ast/nodes/JsxOpeningFragment.ts @@ -0,0 +1,7 @@ +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JsxOpeningFragment extends NodeBase { + type!: NodeType.tJsxOpeningElement; + selfClosing!: boolean; +} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index 4da2c664417..df6b8984706 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -41,11 +41,14 @@ export type tImportExpression = 'ImportExpression'; export type tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export type tImportSpecifier = 'ImportSpecifier'; export type tJsxAttribute = 'JsxAttribute'; +export type tJsxClosingFragment = 'JsxClosingFragment'; export type tJsxElement = 'JsxElement'; export type tJsxEmptyExpr = 'JsxEmptyExpr'; export type tJsxExprContainer = 'JsxExprContainer'; +export type tJsxFragment = 'JsxFragment'; export type tJsxIdentifier = 'JsxIdentifier'; export type tJsxOpeningElement = 'JsxOpeningElement'; +export type tJsxOpeningFragment = 'JsxOpeningFragment'; export type tJsxText = 'JsxText'; export type tLabeledStatement = 'LabeledStatement'; export type tLiteral = 'Literal'; @@ -123,11 +126,14 @@ export const ImportExpression: tImportExpression = 'ImportExpression'; export const ImportNamespaceSpecifier: tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export const ImportSpecifier: tImportSpecifier = 'ImportSpecifier'; export const JsxAttribute: tJsxAttribute = 'JsxAttribute'; +export const JsxClosingFragment: tJsxClosingFragment = 'JsxClosingFragment'; export const JsxElement: tJsxElement = 'JsxElement'; export const JsxEmptyExpr: tJsxEmptyExpr = 'JsxEmptyExpr'; export const JsxExprContainer: tJsxExprContainer = 'JsxExprContainer'; +export const JsxFragment: tJsxFragment = 'JsxFragment'; export const JsxIdentifier: tJsxIdentifier = 'JsxIdentifier'; export const JsxOpeningElement: tJsxOpeningElement = 'JsxOpeningElement'; +export const JsxOpeningFragment: tJsxOpeningFragment = 'JsxOpeningFragment'; export const JsxText: tJsxText = 'JsxText'; export const LabeledStatement: tLabeledStatement = 'LabeledStatement'; export const Literal: tLiteral = 'Literal'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 4757f0d7773..8ea463b45a6 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -41,11 +41,14 @@ import ImportExpression from './ImportExpression'; import ImportNamespaceSpecifier from './ImportNamespaceSpecifier'; import ImportSpecifier from './ImportSpecifier'; import JsxAttribute from './JsxAttribute'; +import JsxClosingFragment from './JsxClosingFragment'; import JsxElement from './JsxElement'; import JsxEmptyExpr from './JsxEmptyExpr'; import JsxExprContainer from './JsxExprContainer'; +import JsxFragment from './JsxFragment'; import JsxIdentifier from './JsxIdentifier'; import JsxOpeningElement from './JsxOpeningElement'; +import JsxOpeningFragment from './JsxOpeningFragment'; import JsxText from './JsxText'; import LabeledStatement from './LabeledStatement'; import Literal from './Literal'; @@ -126,11 +129,14 @@ export const nodeConstructors: Record = { ImportNamespaceSpecifier, ImportSpecifier, JsxAttribute, + JsxClosingFragment, JsxElement, JsxEmptyExpr, JsxExprContainer, + JsxFragment, JsxIdentifier, JsxOpeningElement, + JsxOpeningFragment, JsxText, LabeledStatement, Literal, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index 22f5210dc75..1272175b41e 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -458,6 +458,13 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ name: convertNode(buffer[position + 2], buffer) }; }, + function jsxClosingFragment(position, buffer): JsxClosingFragmentNode { + return { + type: 'JsxClosingFragment', + start: buffer[position], + end: buffer[position + 1] + }; + }, function jsxElement(position, buffer): JsxElementNode { const closingElementPosition = buffer[position + 3]; return { @@ -485,6 +492,16 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ expression: convertNode(buffer[position + 2], buffer) }; }, + function jsxFragment(position, buffer): JsxFragmentNode { + return { + type: 'JsxFragment', + start: buffer[position], + end: buffer[position + 1], + openingFragment: convertNode(buffer[position + 2], buffer), + closingFragment: convertNode(buffer[position + 3], buffer), + children: convertNodeList(buffer[position + 4], buffer) + }; + }, function jsxIdentifier(position, buffer): JsxIdentifierNode { return { type: 'JsxIdentifier', @@ -504,6 +521,13 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ attributes: convertNodeList(buffer[position + 4], buffer) }; }, + function jsxOpeningFragment(position, buffer): JsxOpeningFragmentNode { + return { + type: 'JsxOpeningFragment', + start: buffer[position], + end: buffer[position + 1] + }; + }, function jsxText(position, buffer): JsxTextNode { return { type: 'JsxText', @@ -958,11 +982,14 @@ export type ImportExpressionNode = RollupAstNode< export type ImportNamespaceSpecifierNode = RollupAstNode; export type ImportSpecifierNode = RollupAstNode; export type JsxAttributeNode = RollupAstNode; +export type JsxClosingFragmentNode = RollupAstNode; export type JsxElementNode = RollupAstNode; export type JsxEmptyExprNode = RollupAstNode; export type JsxExprContainerNode = RollupAstNode; +export type JsxFragmentNode = RollupAstNode; export type JsxIdentifierNode = RollupAstNode; export type JsxOpeningElementNode = RollupAstNode; +export type JsxOpeningFragmentNode = RollupAstNode; export type JsxTextNode = RollupAstNode; export type LabeledStatementNode = RollupAstNode; export type LiteralBigIntNode = RollupAstNode; diff --git a/test/form/samples/jsx/preserves-jsx-fragment/_config.js b/test/form/samples/jsx/preserves-jsx-fragment/_config.js new file mode 100644 index 00000000000..85f91019cc6 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-fragment/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX output', + options: { + external: ['react'], + jsx: 'preserve' + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], + verifyAst: false +}); diff --git a/test/form/samples/jsx/preserves-jsx-fragment/_expected.js b/test/form/samples/jsx/preserves-jsx-fragment/_expected.js new file mode 100644 index 00000000000..47bcf4b958f --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-fragment/_expected.js @@ -0,0 +1,5 @@ +import 'react'; + +const result = <>; + +export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-fragment/main.js b/test/form/samples/jsx/preserves-jsx-fragment/main.js new file mode 100644 index 00000000000..3b649ee8f9b --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-fragment/main.js @@ -0,0 +1,4 @@ +import React from "react"; + +const Foo = () => {}; +export const result = <>; From 0579ccfb23625a49091eca5cb31283027d52da77 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 28 Apr 2024 14:17:34 +0200 Subject: [PATCH 11/62] Align AST types with official types and verify This adds acorn-jsx to test the AST against. Tests will fail if the check fails. --- package-lock.json | 1 + package.json | 1 + rust/parse_ast/src/convert_ast/converter.rs | 97 ++++++++++++------- .../convert_ast/converter/ast_constants.rs | 62 ++++++------ .../src/convert_ast/converter/ast_macros.rs | 50 +++++----- scripts/ast-types.js | 39 +++++--- scripts/generate-buffer-parsers.js | 4 +- scripts/generate-buffer-to-ast.js | 4 +- scripts/helpers.js | 9 +- src/ast/bufferParsers.ts | 91 +++++++++-------- src/ast/childNodeKeys.ts | 21 ++-- src/ast/nodes/JSXAttribute.ts | 10 ++ src/ast/nodes/JSXClosingElement.ts | 8 ++ src/ast/nodes/JSXClosingFragment.ts | 6 ++ .../nodes/{JsxElement.ts => JSXElement.ts} | 4 +- src/ast/nodes/JSXEmptyExpression.ts | 6 ++ ...Container.ts => JSXExpressionContainer.ts} | 4 +- .../nodes/{JsxFragment.ts => JSXFragment.ts} | 5 +- .../{JsxIdentifier.ts => JSXIdentifier.ts} | 4 +- src/ast/nodes/JSXOpeningElement.ts | 11 +++ src/ast/nodes/JSXOpeningFragment.ts | 8 ++ src/ast/nodes/{JsxText.ts => JSXText.ts} | 5 +- src/ast/nodes/JsxAttribute.ts | 9 -- src/ast/nodes/JsxClosingFragment.ts | 6 -- src/ast/nodes/JsxEmptyExpr.ts | 6 -- src/ast/nodes/JsxOpeningElement.ts | 10 -- src/ast/nodes/JsxOpeningFragment.ts | 7 -- src/ast/nodes/NodeType.ts | 42 ++++---- src/ast/nodes/index.ts | 42 ++++---- src/utils/bufferToAst.ts | 78 +++++++++------ .../jsx/preserves-jsx-child/_config.js | 3 +- .../jsx/preserves-jsx-closing/_config.js | 3 +- .../preserves-jsx-empty-expression/_config.js | 3 +- .../_config.js | 3 +- .../jsx/preserves-jsx-fragment/_config.js | 3 +- .../samples/jsx/preserves-jsx-text/_config.js | 3 +- .../preserves-jsx-with-attributes/_config.js | 3 +- .../_expected.js | 2 +- .../jsx/preserves-jsx-with-attributes/main.js | 4 +- .../form/samples/jsx/preserves-jsx/_config.js | 3 +- test/utils.js | 3 +- 41 files changed, 387 insertions(+), 296 deletions(-) create mode 100644 src/ast/nodes/JSXAttribute.ts create mode 100644 src/ast/nodes/JSXClosingElement.ts create mode 100644 src/ast/nodes/JSXClosingFragment.ts rename src/ast/nodes/{JsxElement.ts => JSXElement.ts} (71%) create mode 100644 src/ast/nodes/JSXEmptyExpression.ts rename src/ast/nodes/{JsxExprContainer.ts => JSXExpressionContainer.ts} (62%) rename src/ast/nodes/{JsxFragment.ts => JSXFragment.ts} (62%) rename src/ast/nodes/{JsxIdentifier.ts => JSXIdentifier.ts} (54%) create mode 100644 src/ast/nodes/JSXOpeningElement.ts create mode 100644 src/ast/nodes/JSXOpeningFragment.ts rename src/ast/nodes/{JsxText.ts => JSXText.ts} (54%) delete mode 100644 src/ast/nodes/JsxAttribute.ts delete mode 100644 src/ast/nodes/JsxClosingFragment.ts delete mode 100644 src/ast/nodes/JsxEmptyExpr.ts delete mode 100644 src/ast/nodes/JsxOpeningElement.ts delete mode 100644 src/ast/nodes/JsxOpeningFragment.ts diff --git a/package-lock.json b/package-lock.json index 7ce0abdcfc6..451166e7539 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "@vue/language-server": "^2.1.6", "acorn": "^8.12.1", "acorn-import-assertions": "^1.9.0", + "acorn-jsx": "^5.3.2", "buble": "^0.20.0", "builtin-modules": "^4.0.0", "chokidar": "^3.6.0", diff --git a/package.json b/package.json index 19b248575ac..6ccb1c22480 100644 --- a/package.json +++ b/package.json @@ -143,6 +143,7 @@ "@vue/language-server": "^2.1.6", "acorn": "^8.12.1", "acorn-import-assertions": "^1.9.0", + "acorn-jsx": "^5.3.2", "buble": "^0.20.0", "builtin-modules": "^4.0.0", "chokidar": "^3.6.0", diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 7f3eaefe8af..409c74fa568 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,29 +1,33 @@ use swc_common::Span; use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, - ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, - JSXClosingFragment, JSXElement, JSXElementChild, JSXElementName, JSXEmptyExpr, JSXExpr, - JSXExprContainer, JSXFragment, JSXOpeningElement, JSXOpeningFragment, JSXText, Lit, ModuleDecl, - ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, - PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, + ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, + JSXClosingElement, JSXClosingFragment, JSXElement, JSXElementChild, JSXElementName, JSXEmptyExpr, + JSXExpr, JSXExprContainer, JSXFragment, JSXOpeningElement, JSXOpeningFragment, JSXText, Lit, + ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, + Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; use crate::ast_nodes::variable_declaration::VariableDeclaration; use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; use crate::convert_ast::converter::ast_constants::{ - JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_CLOSING_FRAGMENT_RESERVED_BYTES, - JSX_ELEMENT_CHILDREN_OFFSET, JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, - JSX_EMPTY_EXPR_RESERVED_BYTES, JSX_EXPR_CONTAINER_EXPRESSION_OFFSET, - JSX_EXPR_CONTAINER_RESERVED_BYTES, JSX_FRAGMENT_CHILDREN_OFFSET, - JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET, JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET, - JSX_FRAGMENT_RESERVED_BYTES, JSX_IDENTIFIER_NAME_OFFSET, JSX_IDENTIFIER_RESERVED_BYTES, - JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, - JSX_OPENING_ELEMENT_RESERVED_BYTES, JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_TEXT_RESERVED_BYTES, + JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_ATTRIBUTE_VALUE_OFFSET, + JSX_CLOSING_ELEMENT_NAME_OFFSET, JSX_CLOSING_ELEMENT_RESERVED_BYTES, + JSX_CLOSING_FRAGMENT_RESERVED_BYTES, JSX_ELEMENT_CHILDREN_OFFSET, + JSX_ELEMENT_CLOSING_ELEMENT_OFFSET, JSX_ELEMENT_OPENING_ELEMENT_OFFSET, + JSX_ELEMENT_RESERVED_BYTES, JSX_EMPTY_EXPRESSION_RESERVED_BYTES, + JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET, JSX_EXPRESSION_CONTAINER_RESERVED_BYTES, + JSX_FRAGMENT_CHILDREN_OFFSET, JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET, + JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET, JSX_FRAGMENT_RESERVED_BYTES, JSX_IDENTIFIER_NAME_OFFSET, + JSX_IDENTIFIER_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, + JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, + JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_TEXT_RAW_OFFSET, JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, - TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_CLOSING_FRAGMENT, TYPE_JSX_ELEMENT, - TYPE_JSX_EMPTY_EXPR, TYPE_JSX_EXPR_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, - TYPE_JSX_OPENING_ELEMENT, TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_TEXT, + TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_CLOSING_ELEMENT, + TYPE_JSX_CLOSING_FRAGMENT, TYPE_JSX_ELEMENT, TYPE_JSX_EMPTY_EXPRESSION, + TYPE_JSX_EXPRESSION_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, TYPE_JSX_OPENING_ELEMENT, + TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_TEXT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -31,7 +35,7 @@ use crate::convert_ast::converter::string_constants::{ use crate::convert_ast::converter::utf16_positions::{ ConvertedAnnotation, Utf8ToUtf16ByteIndexConverterAndAnnotationHandler, }; -use crate::store_jsx_opening_element_flags; +use crate::store_j_s_x_opening_element_flags; pub(crate) mod analyze_code; pub mod string_constants; @@ -673,6 +677,17 @@ impl<'a> AstConverter<'a> { } } + fn convert_jsx_attribute_value(&mut self, jsx_attribute_value: &JSXAttrValue) { + match jsx_attribute_value { + JSXAttrValue::Lit(literal) => self.convert_literal(literal), + JSXAttrValue::JSXExprContainer(expression_container) => { + self.convert_jsx_expression_container(expression_container) + } + JSXAttrValue::JSXElement(jsx_element) => self.convert_jsx_element(jsx_element), + JSXAttrValue::JSXFragment(jsx_fragment) => self.convert_jsx_fragment(jsx_fragment), + } + } + fn convert_jsx_element(&mut self, jsx_element: &JSXElement) { let end_position = self.add_type_and_start( &TYPE_JSX_ELEMENT, @@ -692,11 +707,11 @@ impl<'a> AstConverter<'a> { true }, ); - // closingElement - // self.update_reference_position(end_position + JSX_ELEMENT_CLOSING_ELEMENT_OFFSET); - // self.store_jsx_closing() - + if let Some(closing) = jsx_element.closing.as_ref() { + self.update_reference_position(end_position + JSX_ELEMENT_CLOSING_ELEMENT_OFFSET); + self.convert_jsx_closing_element(closing); + } // end self.add_end(end_position, &jsx_element.span); } @@ -707,7 +722,7 @@ impl<'a> AstConverter<'a> { self.store_jsx_text(jsx_text); } JSXElementChild::JSXExprContainer(jsx_expr_container) => { - self.store_jsx_expr_container(jsx_expr_container); + self.convert_jsx_expression_container(jsx_expr_container); } JSXElementChild::JSXSpreadChild(_jsx_spread_child) => { // self.store_jsx_spread_child(jsx_spread_child); @@ -722,15 +737,15 @@ impl<'a> AstConverter<'a> { } } - fn store_jsx_expr_container(&mut self, jsx_expr_container: &JSXExprContainer) { + fn convert_jsx_expression_container(&mut self, jsx_expr_container: &JSXExprContainer) { let end_position = self.add_type_and_start( - &TYPE_JSX_EXPR_CONTAINER, + &TYPE_JSX_EXPRESSION_CONTAINER, &jsx_expr_container.span, - JSX_EXPR_CONTAINER_RESERVED_BYTES, + JSX_EXPRESSION_CONTAINER_RESERVED_BYTES, false, ); // expression - self.update_reference_position(end_position + JSX_EXPR_CONTAINER_EXPRESSION_OFFSET); + self.update_reference_position(end_position + JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET); match &jsx_expr_container.expr { JSXExpr::Expr(expression) => { self.convert_expression(expression); @@ -745,9 +760,9 @@ impl<'a> AstConverter<'a> { fn store_jsx_empty_expr(&mut self, jsx_empty_expr: &JSXEmptyExpr) { let end_position = self.add_type_and_start( - &TYPE_JSX_EMPTY_EXPR, + &TYPE_JSX_EMPTY_EXPRESSION, &jsx_empty_expr.span, - JSX_EMPTY_EXPR_RESERVED_BYTES, + JSX_EMPTY_EXPRESSION_RESERVED_BYTES, false, ); // end @@ -763,6 +778,8 @@ impl<'a> AstConverter<'a> { ); // value self.convert_string(&jsx_text.value, end_position + JSX_TEXT_VALUE_OFFSET); + // raw + self.convert_string(&jsx_text.raw, end_position + JSX_TEXT_RAW_OFFSET); // end self.add_end(end_position, &jsx_text.span); } @@ -775,7 +792,7 @@ impl<'a> AstConverter<'a> { false, ); // flags - store_jsx_opening_element_flags!( + store_j_s_x_opening_element_flags!( self, end_position, selfClosing => jsx_opening_element.self_closing @@ -796,6 +813,20 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &jsx_opening_element.span); } + fn convert_jsx_closing_element(&mut self, jsx_closing_element: &JSXClosingElement) { + let end_position = self.add_type_and_start( + &TYPE_JSX_CLOSING_ELEMENT, + &jsx_closing_element.span, + JSX_CLOSING_ELEMENT_RESERVED_BYTES, + false, + ); + // name + self.update_reference_position(end_position + JSX_CLOSING_ELEMENT_NAME_OFFSET); + self.convert_jsx_element_name(&jsx_closing_element.name); + // end + self.add_end(end_position, &jsx_closing_element.span); + } + fn convert_jsx_element_name(&mut self, jsx_element_name: &JSXElementName) { match jsx_element_name { JSXElementName::Ident(identifier) => { @@ -832,10 +863,10 @@ impl<'a> AstConverter<'a> { self.update_reference_position(end_position + JSX_ATTRIBUTE_NAME_OFFSET); self.convert_jsx_attribute_name(&jsx_attribute.name); // value - // jsx_attribute.value.as_ref().map(|jsx_attribute_value| { - // self.update_reference_position(end_position + JSX_ATTRIBUTE_VALUE_OFFSET); - // self.store_jsx_attribute_value(jsx_attribute_value); - // }); + if let Some(jsx_attribute_value) = jsx_attribute.value.as_ref() { + self.update_reference_position(end_position + JSX_ATTRIBUTE_VALUE_OFFSET); + self.convert_jsx_attribute_value(jsx_attribute_value); + }; // end self.add_end(end_position, &jsx_attribute.span); } diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index 172277bf0af..b82479e5552 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -25,29 +25,30 @@ pub const TYPE_IMPORT_ATTRIBUTE: [u8; 4] = 36u32.to_ne_bytes(); pub const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); pub const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); pub const TYPE_JSX_ATTRIBUTE: [u8; 4] = 42u32.to_ne_bytes(); -pub const TYPE_JSX_CLOSING_FRAGMENT: [u8; 4] = 43u32.to_ne_bytes(); -pub const TYPE_JSX_ELEMENT: [u8; 4] = 44u32.to_ne_bytes(); -pub const TYPE_JSX_EMPTY_EXPR: [u8; 4] = 45u32.to_ne_bytes(); -pub const TYPE_JSX_EXPR_CONTAINER: [u8; 4] = 46u32.to_ne_bytes(); -pub const TYPE_JSX_FRAGMENT: [u8; 4] = 47u32.to_ne_bytes(); -pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 48u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 49u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 50u32.to_ne_bytes(); -pub const TYPE_JSX_TEXT: [u8; 4] = 51u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 59u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 60u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 61u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 62u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 63u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 67u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 68u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 69u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 70u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 73u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 80u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 83u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 86u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 87u32.to_ne_bytes(); +pub const TYPE_JSX_CLOSING_ELEMENT: [u8; 4] = 43u32.to_ne_bytes(); +pub const TYPE_JSX_CLOSING_FRAGMENT: [u8; 4] = 44u32.to_ne_bytes(); +pub const TYPE_JSX_ELEMENT: [u8; 4] = 45u32.to_ne_bytes(); +pub const TYPE_JSX_EMPTY_EXPRESSION: [u8; 4] = 46u32.to_ne_bytes(); +pub const TYPE_JSX_EXPRESSION_CONTAINER: [u8; 4] = 47u32.to_ne_bytes(); +pub const TYPE_JSX_FRAGMENT: [u8; 4] = 48u32.to_ne_bytes(); +pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 49u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 50u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 51u32.to_ne_bytes(); +pub const TYPE_JSX_TEXT: [u8; 4] = 52u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 60u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 61u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 62u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 63u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 68u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 69u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 70u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 71u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 74u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 81u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 84u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 87u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 88u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -135,8 +136,12 @@ pub const IMPORT_EXPRESSION_RESERVED_BYTES: usize = 12; pub const IMPORT_EXPRESSION_SOURCE_OFFSET: usize = 4; pub const IMPORT_EXPRESSION_OPTIONS_OFFSET: usize = 8; -pub const JSX_ATTRIBUTE_RESERVED_BYTES: usize = 8; +pub const JSX_ATTRIBUTE_RESERVED_BYTES: usize = 12; pub const JSX_ATTRIBUTE_NAME_OFFSET: usize = 4; +pub const JSX_ATTRIBUTE_VALUE_OFFSET: usize = 8; + +pub const JSX_CLOSING_ELEMENT_RESERVED_BYTES: usize = 8; +pub const JSX_CLOSING_ELEMENT_NAME_OFFSET: usize = 4; pub const JSX_CLOSING_FRAGMENT_RESERVED_BYTES: usize = 4; @@ -145,10 +150,10 @@ pub const JSX_ELEMENT_OPENING_ELEMENT_OFFSET: usize = 4; pub const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 8; pub const JSX_ELEMENT_CHILDREN_OFFSET: usize = 12; -pub const JSX_EMPTY_EXPR_RESERVED_BYTES: usize = 4; +pub const JSX_EMPTY_EXPRESSION_RESERVED_BYTES: usize = 4; -pub const JSX_EXPR_CONTAINER_RESERVED_BYTES: usize = 8; -pub const JSX_EXPR_CONTAINER_EXPRESSION_OFFSET: usize = 4; +pub const JSX_EXPRESSION_CONTAINER_RESERVED_BYTES: usize = 8; +pub const JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET: usize = 4; pub const JSX_FRAGMENT_RESERVED_BYTES: usize = 16; pub const JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET: usize = 4; @@ -164,8 +169,9 @@ pub const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; pub const JSX_OPENING_FRAGMENT_RESERVED_BYTES: usize = 4; -pub const JSX_TEXT_RESERVED_BYTES: usize = 8; +pub const JSX_TEXT_RESERVED_BYTES: usize = 12; pub const JSX_TEXT_VALUE_OFFSET: usize = 4; +pub const JSX_TEXT_RAW_OFFSET: usize = 8; pub const MEMBER_EXPRESSION_RESERVED_BYTES: usize = 16; pub const MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 8; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index 806c9c5d386..afb3ba95795 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -319,7 +319,7 @@ macro_rules! store_import_specifier { macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&52u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&53u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&53u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&54u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &54u32.to_ne_bytes(), + &55u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&64u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &79u32.to_ne_bytes(), + &80u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&82u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&82u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&83u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&84u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&85u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &85u32.to_ne_bytes(), + &86u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&88u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&89u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &89u32.to_ne_bytes(), + &90u32.to_ne_bytes(), &$span, 12, false, @@ -775,7 +775,7 @@ macro_rules! store_function_declaration_flags { } #[macro_export] -macro_rules! store_jsx_opening_element_flags { +macro_rules! store_j_s_x_opening_element_flags { ($self:expr, $end_position:expr, selfClosing => $selfClosing_value:expr) => { let _: &mut AstConverter = $self; let _: usize = $end_position; diff --git a/scripts/ast-types.js b/scripts/ast-types.js index 556b2db2567..ac2bf94b634 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -388,20 +388,25 @@ export const AST_NODES = { imported: 'local' } }, - JsxAttribute: { + JSXAttribute: { estreeType: 'any', fields: [ - ['name', 'Node'] - // ['value', 'OptionalString'] + ['name', 'Node'], + ['value', 'OptionalNode'] ], useMacro: false }, - JsxClosingFragment: { + JSXClosingElement: { + estreeType: 'any', + fields: [['name', 'Node']], + useMacro: false + }, + JSXClosingFragment: { estreeType: 'any', fields: [], useMacro: false }, - JsxElement: { + JSXElement: { estreeType: 'any', fields: [ ['openingElement', 'Node'], @@ -410,16 +415,16 @@ export const AST_NODES = { ], useMacro: false }, - JsxEmptyExpr: { + JSXEmptyExpression: { estreeType: 'any', useMacro: false }, - JsxExprContainer: { + JSXExpressionContainer: { estreeType: 'any', fields: [['expression', 'Node']], useMacro: false }, - JsxFragment: { + JSXFragment: { estreeType: 'any', fields: [ ['openingFragment', 'Node'], @@ -428,12 +433,12 @@ export const AST_NODES = { ], useMacro: false }, - JsxIdentifier: { + JSXIdentifier: { estreeType: 'any', fields: [['name', 'String']], useMacro: false }, - JsxOpeningElement: { + JSXOpeningElement: { estreeType: 'any', fields: [ ['name', 'Node'], @@ -442,14 +447,20 @@ export const AST_NODES = { flags: ['selfClosing'], useMacro: false }, - JsxOpeningFragment: { + JSXOpeningFragment: { + additionalFields: { + attributes: '[]', + selfClosing: 'false' + }, estreeType: 'any', - fields: [], useMacro: false }, - JsxText: { + JSXText: { estreeType: 'any', - fields: [['value', 'String']], + fields: [ + ['value', 'String'], + ['raw', 'String'] + ], useMacro: false }, LabeledStatement: { diff --git a/scripts/generate-buffer-parsers.js b/scripts/generate-buffer-parsers.js index 3292aa272d3..d6f9ce6e64a 100644 --- a/scripts/generate-buffer-parsers.js +++ b/scripts/generate-buffer-parsers.js @@ -1,6 +1,6 @@ import { writeFile } from 'node:fs/promises'; import { astNodeNamesWithFieldOrder } from './ast-types.js'; -import { firstLetterLowercase, generateNotEditFilesComment, lintTsFile } from './helpers.js'; +import { firstLettersLowercase, generateNotEditFilesComment, lintTsFile } from './helpers.js'; const notEditFilesComment = generateNotEditFilesComment(import.meta.url); @@ -60,7 +60,7 @@ const jsConverters = astNodeNamesWithFieldOrder.map(({ name, fields, node, origi parameters.push('position, buffer'); } } - return `function ${firstLetterLowercase(name)} (${parameters.join(', ')}) { + return `function ${firstLettersLowercase(name)} (${parameters.join(', ')}) { ${definitions.join('')}}`; }); diff --git a/scripts/generate-buffer-to-ast.js b/scripts/generate-buffer-to-ast.js index 6199e15abb2..4a0b971dae3 100644 --- a/scripts/generate-buffer-to-ast.js +++ b/scripts/generate-buffer-to-ast.js @@ -1,6 +1,6 @@ import { writeFile } from 'node:fs/promises'; import { astNodeNamesWithFieldOrder } from './ast-types.js'; -import { firstLetterLowercase, generateNotEditFilesComment, lintTsFile } from './helpers.js'; +import { firstLettersLowercase, generateNotEditFilesComment, lintTsFile } from './helpers.js'; const notEditFilesComment = generateNotEditFilesComment(import.meta.url); @@ -38,7 +38,7 @@ const jsConverters = astNodeNamesWithFieldOrder.map(({ name, fields, node, origi ...getFixedProperties(node), ...Object.entries(node.additionalFields || []).map(([key, value]) => `${key}: ${value}`) ]; - return `function ${firstLetterLowercase(name)} (position, buffer): ${name}Node { + return `function ${firstLettersLowercase(name)} (position, buffer): ${name}Node { ${definitions.join('')}return { type: '${node.astType || name}', start: buffer[position], diff --git a/scripts/helpers.js b/scripts/helpers.js index 9e1d9016096..7b913c4f700 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -99,11 +99,14 @@ export function lintRustFile(file) { } /** + * Replace the first letters with lowercase while maintaining camel casing * @param {string} string * @returns {string} */ -export function firstLetterLowercase(string) { - return string[0].toLowerCase() + string.slice(1); +export function firstLettersLowercase(string) { + return string.replace(/^[A-Z]+/, match => + match.length === 1 ? match.toLowerCase() : match.slice(0, -1).toLowerCase() + match.slice(-1) + ); } /** @@ -119,7 +122,7 @@ export function toSnakeCase(string) { * @returns {string} */ export function toScreamingSnakeCase(string) { - return string.replace(/(? void)[ node.imported = importedPosition === 0 ? node.local : convertNode(node, scope, importedPosition, buffer); }, - function jsxAttribute(node: JsxAttribute, position, buffer) { + function jsxAttribute(node: JSXAttribute, position, buffer) { + const { scope } = node; + node.name = convertNode(node, scope, buffer[position], buffer); + const valuePosition = buffer[position + 1]; + node.value = valuePosition === 0 ? null : convertNode(node, scope, valuePosition, buffer); + }, + function jsxClosingElement(node: JSXClosingElement, position, buffer) { const { scope } = node; node.name = convertNode(node, scope, buffer[position], buffer); }, function jsxClosingFragment() {}, - function jsxElement(node: JsxElement, position, buffer) { + function jsxElement(node: JSXElement, position, buffer) { const { scope } = node; node.openingElement = convertNode(node, scope, buffer[position], buffer); const closingElementPosition = buffer[position + 1]; @@ -608,30 +617,34 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ : convertNode(node, scope, closingElementPosition, buffer); node.children = convertNodeList(node, scope, buffer[position + 2], buffer); }, - function jsxEmptyExpr() {}, - function jsxExprContainer(node: JsxExprContainer, position, buffer) { + function jsxEmptyExpression() {}, + function jsxExpressionContainer(node: JSXExpressionContainer, position, buffer) { const { scope } = node; node.expression = convertNode(node, scope, buffer[position], buffer); }, - function jsxFragment(node: JsxFragment, position, buffer) { + function jsxFragment(node: JSXFragment, position, buffer) { const { scope } = node; node.openingFragment = convertNode(node, scope, buffer[position], buffer); node.closingFragment = convertNode(node, scope, buffer[position + 1], buffer); node.children = convertNodeList(node, scope, buffer[position + 2], buffer); }, - function jsxIdentifier(node: JsxIdentifier, position, buffer) { + function jsxIdentifier(node: JSXIdentifier, position, buffer) { node.name = buffer.convertString(buffer[position]); }, - function jsxOpeningElement(node: JsxOpeningElement, position, buffer) { + function jsxOpeningElement(node: JSXOpeningElement, position, buffer) { const { scope } = node; const flags = buffer[position]; node.selfClosing = (flags & 1) === 1; node.name = convertNode(node, scope, buffer[position + 1], buffer); node.attributes = convertNodeList(node, scope, buffer[position + 2], buffer); }, - function jsxOpeningFragment() {}, - function jsxText(node: JsxText, position, buffer) { + function jsxOpeningFragment(node: JSXOpeningFragment) { + node.attributes = []; + node.selfClosing = false; + }, + function jsxText(node: JSXText, position, buffer) { node.value = buffer.convertString(buffer[position]); + node.raw = buffer.convertString(buffer[position + 1]); }, function labeledStatement(node: LabeledStatement, position, buffer) { const { scope } = node; diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index 95df38b54d2..44f35c2238d 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -41,16 +41,17 @@ export const childNodeKeys: Record = { ImportExpression: ['source', 'options'], ImportNamespaceSpecifier: ['local'], ImportSpecifier: ['imported', 'local'], - JsxAttribute: ['name'], - JsxClosingFragment: [], - JsxElement: ['openingElement', 'closingElement', 'children'], - JsxEmptyExpr: [], - JsxExprContainer: ['expression'], - JsxFragment: ['openingFragment', 'closingFragment', 'children'], - JsxIdentifier: [], - JsxOpeningElement: ['name', 'attributes'], - JsxOpeningFragment: [], - JsxText: [], + JSXAttribute: ['name', 'value'], + JSXClosingElement: ['name'], + JSXClosingFragment: [], + JSXElement: ['openingElement', 'closingElement', 'children'], + JSXEmptyExpression: [], + JSXExpressionContainer: ['expression'], + JSXFragment: ['openingFragment', 'closingFragment', 'children'], + JSXIdentifier: [], + JSXOpeningElement: ['name', 'attributes'], + JSXOpeningFragment: [], + JSXText: [], LabeledStatement: ['label', 'body'], Literal: [], LogicalExpression: ['left', 'right'], diff --git a/src/ast/nodes/JSXAttribute.ts b/src/ast/nodes/JSXAttribute.ts new file mode 100644 index 00000000000..a7430aeef9f --- /dev/null +++ b/src/ast/nodes/JSXAttribute.ts @@ -0,0 +1,10 @@ +import type JSXIdentifier from './JSXIdentifier'; +import type * as NodeType from './NodeType'; +import type { ExpressionNode } from './shared/Node'; +import { NodeBase } from './shared/Node'; + +export default class JSXAttribute extends NodeBase { + declare name: JSXIdentifier; + declare value: ExpressionNode | null; + declare type: NodeType.tJSXAttribute; +} diff --git a/src/ast/nodes/JSXClosingElement.ts b/src/ast/nodes/JSXClosingElement.ts new file mode 100644 index 00000000000..97e8e896175 --- /dev/null +++ b/src/ast/nodes/JSXClosingElement.ts @@ -0,0 +1,8 @@ +import type JSXIdentifier from './JSXIdentifier'; +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JSXClosingElement extends NodeBase { + type!: NodeType.tJSXClosingElement; + name!: JSXIdentifier; +} diff --git a/src/ast/nodes/JSXClosingFragment.ts b/src/ast/nodes/JSXClosingFragment.ts new file mode 100644 index 00000000000..5a3b0c2e253 --- /dev/null +++ b/src/ast/nodes/JSXClosingFragment.ts @@ -0,0 +1,6 @@ +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JSXClosingFragment extends NodeBase { + declare type: NodeType.tJSXElement; +} diff --git a/src/ast/nodes/JsxElement.ts b/src/ast/nodes/JSXElement.ts similarity index 71% rename from src/ast/nodes/JsxElement.ts rename to src/ast/nodes/JSXElement.ts index d89dec4b247..0cbe9b76c32 100644 --- a/src/ast/nodes/JsxElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -1,9 +1,9 @@ import type * as NodeType from './NodeType'; import { type ExpressionNode, NodeBase } from './shared/Node'; -export default class JsxElement extends NodeBase { +export default class JSXElement extends NodeBase { declare closingElement: unknown; declare openingElement: unknown; - declare type: NodeType.tJsxElement; + declare type: NodeType.tJSXElement; declare children: ExpressionNode[]; } diff --git a/src/ast/nodes/JSXEmptyExpression.ts b/src/ast/nodes/JSXEmptyExpression.ts new file mode 100644 index 00000000000..87d3b29a1b3 --- /dev/null +++ b/src/ast/nodes/JSXEmptyExpression.ts @@ -0,0 +1,6 @@ +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JSXEmptyExpression extends NodeBase { + type!: NodeType.tJSXEmptyExpression; +} diff --git a/src/ast/nodes/JsxExprContainer.ts b/src/ast/nodes/JSXExpressionContainer.ts similarity index 62% rename from src/ast/nodes/JsxExprContainer.ts rename to src/ast/nodes/JSXExpressionContainer.ts index d25a83a8969..09f68b47d77 100644 --- a/src/ast/nodes/JsxExprContainer.ts +++ b/src/ast/nodes/JSXExpressionContainer.ts @@ -2,7 +2,7 @@ import type * as NodeType from './NodeType'; import type { ExpressionNode } from './shared/Node'; import { NodeBase } from './shared/Node'; -export default class JsxExprContainer extends NodeBase { - type!: NodeType.tJsxExprContainer; +export default class JSXExpressionContainer extends NodeBase { + type!: NodeType.tJSXExpressionContainer; expression!: ExpressionNode; } diff --git a/src/ast/nodes/JsxFragment.ts b/src/ast/nodes/JSXFragment.ts similarity index 62% rename from src/ast/nodes/JsxFragment.ts rename to src/ast/nodes/JSXFragment.ts index 4cc9a2a8719..dc8a8ba8abf 100644 --- a/src/ast/nodes/JsxFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -1,9 +1,10 @@ +import type JSXOpeningFragment from './JSXOpeningFragment'; import type * as NodeType from './NodeType'; import { type ExpressionNode, NodeBase } from './shared/Node'; export default class JsxElement extends NodeBase { declare closingFragment: unknown; - declare openingFragment: unknown; - declare type: NodeType.tJsxElement; + declare openingFragment: JSXOpeningFragment; + declare type: NodeType.tJSXElement; declare children: ExpressionNode[]; } diff --git a/src/ast/nodes/JsxIdentifier.ts b/src/ast/nodes/JSXIdentifier.ts similarity index 54% rename from src/ast/nodes/JsxIdentifier.ts rename to src/ast/nodes/JSXIdentifier.ts index 839ab7e5b9e..5277e778297 100644 --- a/src/ast/nodes/JsxIdentifier.ts +++ b/src/ast/nodes/JSXIdentifier.ts @@ -1,7 +1,7 @@ import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; -export default class JsxIdentifier extends NodeBase { - type!: NodeType.tJsxIdentifier; +export default class JSXIdentifier extends NodeBase { + type!: NodeType.tJSXIdentifier; name!: string; } diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts new file mode 100644 index 00000000000..f771de4252b --- /dev/null +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -0,0 +1,11 @@ +import type JSXAttribute from './JSXAttribute'; +import type JSXIdentifier from './JSXIdentifier'; +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JSXOpeningElement extends NodeBase { + type!: NodeType.tJSXOpeningElement; + selfClosing!: boolean; + name!: JSXIdentifier; + attributes!: JSXAttribute[]; +} diff --git a/src/ast/nodes/JSXOpeningFragment.ts b/src/ast/nodes/JSXOpeningFragment.ts new file mode 100644 index 00000000000..c92161303c4 --- /dev/null +++ b/src/ast/nodes/JSXOpeningFragment.ts @@ -0,0 +1,8 @@ +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JSXOpeningFragment extends NodeBase { + type!: NodeType.tJSXOpeningElement; + attributes!: never[]; + selfClosing!: false; +} diff --git a/src/ast/nodes/JsxText.ts b/src/ast/nodes/JSXText.ts similarity index 54% rename from src/ast/nodes/JsxText.ts rename to src/ast/nodes/JSXText.ts index a732022de96..5045952aa09 100644 --- a/src/ast/nodes/JsxText.ts +++ b/src/ast/nodes/JSXText.ts @@ -1,7 +1,8 @@ import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; -export default class JsxText extends NodeBase { - type!: NodeType.tJsxText; +export default class JSXText extends NodeBase { + type!: NodeType.tJSXText; value!: string; + raw!: string; } diff --git a/src/ast/nodes/JsxAttribute.ts b/src/ast/nodes/JsxAttribute.ts deleted file mode 100644 index 70b23ac4897..00000000000 --- a/src/ast/nodes/JsxAttribute.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type JsxIdentifier from './JsxIdentifier'; -import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; - -export default class JsxAttribute extends NodeBase { - declare name: JsxIdentifier; - declare value: undefined; - declare type: NodeType.tJsxAttribute; -} diff --git a/src/ast/nodes/JsxClosingFragment.ts b/src/ast/nodes/JsxClosingFragment.ts deleted file mode 100644 index 60c1c3e0d01..00000000000 --- a/src/ast/nodes/JsxClosingFragment.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; - -export default class JsxClosingFragment extends NodeBase { - declare type: NodeType.tJsxElement; -} diff --git a/src/ast/nodes/JsxEmptyExpr.ts b/src/ast/nodes/JsxEmptyExpr.ts deleted file mode 100644 index a19c10eb633..00000000000 --- a/src/ast/nodes/JsxEmptyExpr.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; - -export default class JsxEmptyExpr extends NodeBase { - type!: NodeType.tJsxEmptyExpr; -} diff --git a/src/ast/nodes/JsxOpeningElement.ts b/src/ast/nodes/JsxOpeningElement.ts deleted file mode 100644 index 07b33940c56..00000000000 --- a/src/ast/nodes/JsxOpeningElement.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type JsxIdentifier from './JsxIdentifier'; -import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; - -export default class JsxOpeningElement extends NodeBase { - type!: NodeType.tJsxOpeningElement; - selfClosing!: boolean; - name!: JsxIdentifier; - attributes!: any; // TODO JSXAttribute -} diff --git a/src/ast/nodes/JsxOpeningFragment.ts b/src/ast/nodes/JsxOpeningFragment.ts deleted file mode 100644 index 72a0199778b..00000000000 --- a/src/ast/nodes/JsxOpeningFragment.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; - -export default class JsxOpeningFragment extends NodeBase { - type!: NodeType.tJsxOpeningElement; - selfClosing!: boolean; -} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index df6b8984706..38f6ba423a2 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -40,16 +40,17 @@ export type tImportDefaultSpecifier = 'ImportDefaultSpecifier'; export type tImportExpression = 'ImportExpression'; export type tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export type tImportSpecifier = 'ImportSpecifier'; -export type tJsxAttribute = 'JsxAttribute'; -export type tJsxClosingFragment = 'JsxClosingFragment'; -export type tJsxElement = 'JsxElement'; -export type tJsxEmptyExpr = 'JsxEmptyExpr'; -export type tJsxExprContainer = 'JsxExprContainer'; -export type tJsxFragment = 'JsxFragment'; -export type tJsxIdentifier = 'JsxIdentifier'; -export type tJsxOpeningElement = 'JsxOpeningElement'; -export type tJsxOpeningFragment = 'JsxOpeningFragment'; -export type tJsxText = 'JsxText'; +export type tJSXAttribute = 'JSXAttribute'; +export type tJSXClosingElement = 'JSXClosingElement'; +export type tJSXClosingFragment = 'JSXClosingFragment'; +export type tJSXElement = 'JSXElement'; +export type tJSXEmptyExpression = 'JSXEmptyExpression'; +export type tJSXExpressionContainer = 'JSXExpressionContainer'; +export type tJSXFragment = 'JSXFragment'; +export type tJSXIdentifier = 'JSXIdentifier'; +export type tJSXOpeningElement = 'JSXOpeningElement'; +export type tJSXOpeningFragment = 'JSXOpeningFragment'; +export type tJSXText = 'JSXText'; export type tLabeledStatement = 'LabeledStatement'; export type tLiteral = 'Literal'; export type tLogicalExpression = 'LogicalExpression'; @@ -125,16 +126,17 @@ export const ImportDefaultSpecifier: tImportDefaultSpecifier = 'ImportDefaultSpe export const ImportExpression: tImportExpression = 'ImportExpression'; export const ImportNamespaceSpecifier: tImportNamespaceSpecifier = 'ImportNamespaceSpecifier'; export const ImportSpecifier: tImportSpecifier = 'ImportSpecifier'; -export const JsxAttribute: tJsxAttribute = 'JsxAttribute'; -export const JsxClosingFragment: tJsxClosingFragment = 'JsxClosingFragment'; -export const JsxElement: tJsxElement = 'JsxElement'; -export const JsxEmptyExpr: tJsxEmptyExpr = 'JsxEmptyExpr'; -export const JsxExprContainer: tJsxExprContainer = 'JsxExprContainer'; -export const JsxFragment: tJsxFragment = 'JsxFragment'; -export const JsxIdentifier: tJsxIdentifier = 'JsxIdentifier'; -export const JsxOpeningElement: tJsxOpeningElement = 'JsxOpeningElement'; -export const JsxOpeningFragment: tJsxOpeningFragment = 'JsxOpeningFragment'; -export const JsxText: tJsxText = 'JsxText'; +export const JSXAttribute: tJSXAttribute = 'JSXAttribute'; +export const JSXClosingElement: tJSXClosingElement = 'JSXClosingElement'; +export const JSXClosingFragment: tJSXClosingFragment = 'JSXClosingFragment'; +export const JSXElement: tJSXElement = 'JSXElement'; +export const JSXEmptyExpression: tJSXEmptyExpression = 'JSXEmptyExpression'; +export const JSXExpressionContainer: tJSXExpressionContainer = 'JSXExpressionContainer'; +export const JSXFragment: tJSXFragment = 'JSXFragment'; +export const JSXIdentifier: tJSXIdentifier = 'JSXIdentifier'; +export const JSXOpeningElement: tJSXOpeningElement = 'JSXOpeningElement'; +export const JSXOpeningFragment: tJSXOpeningFragment = 'JSXOpeningFragment'; +export const JSXText: tJSXText = 'JSXText'; export const LabeledStatement: tLabeledStatement = 'LabeledStatement'; export const Literal: tLiteral = 'Literal'; export const LogicalExpression: tLogicalExpression = 'LogicalExpression'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 8ea463b45a6..a203d713e01 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -40,16 +40,17 @@ import ImportDefaultSpecifier from './ImportDefaultSpecifier'; import ImportExpression from './ImportExpression'; import ImportNamespaceSpecifier from './ImportNamespaceSpecifier'; import ImportSpecifier from './ImportSpecifier'; -import JsxAttribute from './JsxAttribute'; -import JsxClosingFragment from './JsxClosingFragment'; -import JsxElement from './JsxElement'; -import JsxEmptyExpr from './JsxEmptyExpr'; -import JsxExprContainer from './JsxExprContainer'; -import JsxFragment from './JsxFragment'; -import JsxIdentifier from './JsxIdentifier'; -import JsxOpeningElement from './JsxOpeningElement'; -import JsxOpeningFragment from './JsxOpeningFragment'; -import JsxText from './JsxText'; +import JSXAttribute from './JSXAttribute'; +import JSXClosingElement from './JSXClosingElement'; +import JSXClosingFragment from './JSXClosingFragment'; +import JSXElement from './JSXElement'; +import JSXEmptyExpression from './JSXEmptyExpression'; +import JSXExpressionContainer from './JSXExpressionContainer'; +import JSXFragment from './JSXFragment'; +import JSXIdentifier from './JSXIdentifier'; +import JSXOpeningElement from './JSXOpeningElement'; +import JSXOpeningFragment from './JSXOpeningFragment'; +import JSXText from './JSXText'; import LabeledStatement from './LabeledStatement'; import Literal from './Literal'; import LogicalExpression from './LogicalExpression'; @@ -128,16 +129,17 @@ export const nodeConstructors: Record = { ImportExpression, ImportNamespaceSpecifier, ImportSpecifier, - JsxAttribute, - JsxClosingFragment, - JsxElement, - JsxEmptyExpr, - JsxExprContainer, - JsxFragment, - JsxIdentifier, - JsxOpeningElement, - JsxOpeningFragment, - JsxText, + JSXAttribute, + JSXClosingElement, + JSXClosingFragment, + JSXElement, + JSXEmptyExpression, + JSXExpressionContainer, + JSXFragment, + JSXIdentifier, + JSXOpeningElement, + JSXOpeningFragment, + JSXText, LabeledStatement, Literal, LogicalExpression, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index 1272175b41e..c8f73f6e597 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -450,25 +450,35 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ local }; }, - function jsxAttribute(position, buffer): JsxAttributeNode { + function jsxAttribute(position, buffer): JSXAttributeNode { + const valuePosition = buffer[position + 3]; return { - type: 'JsxAttribute', + type: 'JSXAttribute', + start: buffer[position], + end: buffer[position + 1], + name: convertNode(buffer[position + 2], buffer), + value: valuePosition === 0 ? null : convertNode(valuePosition, buffer) + }; + }, + function jsxClosingElement(position, buffer): JSXClosingElementNode { + return { + type: 'JSXClosingElement', start: buffer[position], end: buffer[position + 1], name: convertNode(buffer[position + 2], buffer) }; }, - function jsxClosingFragment(position, buffer): JsxClosingFragmentNode { + function jsxClosingFragment(position, buffer): JSXClosingFragmentNode { return { - type: 'JsxClosingFragment', + type: 'JSXClosingFragment', start: buffer[position], end: buffer[position + 1] }; }, - function jsxElement(position, buffer): JsxElementNode { + function jsxElement(position, buffer): JSXElementNode { const closingElementPosition = buffer[position + 3]; return { - type: 'JsxElement', + type: 'JSXElement', start: buffer[position], end: buffer[position + 1], openingElement: convertNode(buffer[position + 2], buffer), @@ -477,24 +487,24 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ children: convertNodeList(buffer[position + 4], buffer) }; }, - function jsxEmptyExpr(position, buffer): JsxEmptyExprNode { + function jsxEmptyExpression(position, buffer): JSXEmptyExpressionNode { return { - type: 'JsxEmptyExpr', + type: 'JSXEmptyExpression', start: buffer[position], end: buffer[position + 1] }; }, - function jsxExprContainer(position, buffer): JsxExprContainerNode { + function jsxExpressionContainer(position, buffer): JSXExpressionContainerNode { return { - type: 'JsxExprContainer', + type: 'JSXExpressionContainer', start: buffer[position], end: buffer[position + 1], expression: convertNode(buffer[position + 2], buffer) }; }, - function jsxFragment(position, buffer): JsxFragmentNode { + function jsxFragment(position, buffer): JSXFragmentNode { return { - type: 'JsxFragment', + type: 'JSXFragment', start: buffer[position], end: buffer[position + 1], openingFragment: convertNode(buffer[position + 2], buffer), @@ -502,18 +512,18 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ children: convertNodeList(buffer[position + 4], buffer) }; }, - function jsxIdentifier(position, buffer): JsxIdentifierNode { + function jsxIdentifier(position, buffer): JSXIdentifierNode { return { - type: 'JsxIdentifier', + type: 'JSXIdentifier', start: buffer[position], end: buffer[position + 1], name: buffer.convertString(buffer[position + 2]) }; }, - function jsxOpeningElement(position, buffer): JsxOpeningElementNode { + function jsxOpeningElement(position, buffer): JSXOpeningElementNode { const flags = buffer[position + 2]; return { - type: 'JsxOpeningElement', + type: 'JSXOpeningElement', start: buffer[position], end: buffer[position + 1], selfClosing: (flags & 1) === 1, @@ -521,19 +531,22 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ attributes: convertNodeList(buffer[position + 4], buffer) }; }, - function jsxOpeningFragment(position, buffer): JsxOpeningFragmentNode { + function jsxOpeningFragment(position, buffer): JSXOpeningFragmentNode { return { - type: 'JsxOpeningFragment', + type: 'JSXOpeningFragment', start: buffer[position], - end: buffer[position + 1] + end: buffer[position + 1], + attributes: [], + selfClosing: false }; }, - function jsxText(position, buffer): JsxTextNode { + function jsxText(position, buffer): JSXTextNode { return { - type: 'JsxText', + type: 'JSXText', start: buffer[position], end: buffer[position + 1], - value: buffer.convertString(buffer[position + 2]) + value: buffer.convertString(buffer[position + 2]), + raw: buffer.convertString(buffer[position + 3]) }; }, function labeledStatement(position, buffer): LabeledStatementNode { @@ -981,16 +994,17 @@ export type ImportExpressionNode = RollupAstNode< >; export type ImportNamespaceSpecifierNode = RollupAstNode; export type ImportSpecifierNode = RollupAstNode; -export type JsxAttributeNode = RollupAstNode; -export type JsxClosingFragmentNode = RollupAstNode; -export type JsxElementNode = RollupAstNode; -export type JsxEmptyExprNode = RollupAstNode; -export type JsxExprContainerNode = RollupAstNode; -export type JsxFragmentNode = RollupAstNode; -export type JsxIdentifierNode = RollupAstNode; -export type JsxOpeningElementNode = RollupAstNode; -export type JsxOpeningFragmentNode = RollupAstNode; -export type JsxTextNode = RollupAstNode; +export type JSXAttributeNode = RollupAstNode; +export type JSXClosingElementNode = RollupAstNode; +export type JSXClosingFragmentNode = RollupAstNode; +export type JSXElementNode = RollupAstNode; +export type JSXEmptyExpressionNode = RollupAstNode; +export type JSXExpressionContainerNode = RollupAstNode; +export type JSXFragmentNode = RollupAstNode; +export type JSXIdentifierNode = RollupAstNode; +export type JSXOpeningElementNode = RollupAstNode; +export type JSXOpeningFragmentNode = RollupAstNode; +export type JSXTextNode = RollupAstNode; export type LabeledStatementNode = RollupAstNode; export type LiteralBigIntNode = RollupAstNode; export type LiteralBooleanNode = RollupAstNode; diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js index 85f91019cc6..78de66a33bd 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -5,6 +5,5 @@ module.exports = defineTest({ external: ['react'], jsx: 'preserve' }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], - verifyAst: false + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] }); diff --git a/test/form/samples/jsx/preserves-jsx-closing/_config.js b/test/form/samples/jsx/preserves-jsx-closing/_config.js index 85f91019cc6..78de66a33bd 100644 --- a/test/form/samples/jsx/preserves-jsx-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-closing/_config.js @@ -5,6 +5,5 @@ module.exports = defineTest({ external: ['react'], jsx: 'preserve' }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], - verifyAst: false + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] }); diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js index 85f91019cc6..78de66a33bd 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js @@ -5,6 +5,5 @@ module.exports = defineTest({ external: ['react'], jsx: 'preserve' }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], - verifyAst: false + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] }); diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js index 85f91019cc6..78de66a33bd 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js @@ -5,6 +5,5 @@ module.exports = defineTest({ external: ['react'], jsx: 'preserve' }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], - verifyAst: false + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] }); diff --git a/test/form/samples/jsx/preserves-jsx-fragment/_config.js b/test/form/samples/jsx/preserves-jsx-fragment/_config.js index 85f91019cc6..78de66a33bd 100644 --- a/test/form/samples/jsx/preserves-jsx-fragment/_config.js +++ b/test/form/samples/jsx/preserves-jsx-fragment/_config.js @@ -5,6 +5,5 @@ module.exports = defineTest({ external: ['react'], jsx: 'preserve' }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], - verifyAst: false + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] }); diff --git a/test/form/samples/jsx/preserves-jsx-text/_config.js b/test/form/samples/jsx/preserves-jsx-text/_config.js index 85f91019cc6..78de66a33bd 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_config.js +++ b/test/form/samples/jsx/preserves-jsx-text/_config.js @@ -5,6 +5,5 @@ module.exports = defineTest({ external: ['react'], jsx: 'preserve' }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], - verifyAst: false + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] }); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js b/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js index fc7469ffeed..de881e8ad62 100644 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js @@ -5,6 +5,5 @@ module.exports = defineTest({ external: ['react'], jsx: 'preserve' }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], - verifyAst: false + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] }); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js b/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js index ae7bc58b591..51b08f79ed5 100644 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js @@ -1,5 +1,5 @@ import 'react'; -const result = ; +const result = ; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/main.js b/test/form/samples/jsx/preserves-jsx-with-attributes/main.js index 98af3100fbd..df93c1f9854 100644 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/main.js +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/main.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; const Foo = () => {}; -export const result = ; +export const result = ; diff --git a/test/form/samples/jsx/preserves-jsx/_config.js b/test/form/samples/jsx/preserves-jsx/_config.js index 85f91019cc6..78de66a33bd 100644 --- a/test/form/samples/jsx/preserves-jsx/_config.js +++ b/test/form/samples/jsx/preserves-jsx/_config.js @@ -5,6 +5,5 @@ module.exports = defineTest({ external: ['react'], jsx: 'preserve' }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'], - verifyAst: false + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] }); diff --git a/test/utils.js b/test/utils.js index 43f1dcb7592..3810211bc2e 100644 --- a/test/utils.js +++ b/test/utils.js @@ -23,6 +23,7 @@ const path = require('node:path'); const { platform, version } = require('node:process'); const { Parser } = require('acorn'); const { importAssertions } = require('acorn-import-assertions'); +const jsx = require('acorn-jsx'); const fixturify = require('fixturify'); if (!globalThis.defineTest) { @@ -454,7 +455,7 @@ exports.replaceDirectoryInStringifiedObject = function replaceDirectoryInStringi /** @type {boolean} */ exports.hasEsBuild = existsSync(path.join(__dirname, '../dist/es')); -const acornParser = Parser.extend(importAssertions); +const acornParser = Parser.extend(importAssertions, jsx()); exports.verifyAstPlugin = { name: 'verify-ast', From d2f9b94f0e73151dc4a01e6e88bdff93535fe173 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 28 Apr 2024 14:33:18 +0200 Subject: [PATCH 12/62] Sort converters into alphabetical order --- rust/parse_ast/src/convert_ast/converter.rs | 318 ++++++++++---------- 1 file changed, 158 insertions(+), 160 deletions(-) diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 409c74fa568..0719053c240 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -433,6 +433,71 @@ impl<'a> AstConverter<'a> { } } + fn convert_jsx_attribute_name(&mut self, jsx_attribute_name: &JSXAttrName) { + match jsx_attribute_name { + JSXAttrName::Ident(identifier) => { + self.store_jsx_identifier(identifier); + } + JSXAttrName::JSXNamespacedName(_jsx_namespaced_name) => { + unimplemented!("JSXElementName::JSXNamespacedName") + } + } + } + + fn convert_jsx_attribute_or_spread(&mut self, jsx_attribute_or_spread: &JSXAttrOrSpread) { + match jsx_attribute_or_spread { + JSXAttrOrSpread::JSXAttr(jsx_attribute) => { + self.convert_jsx_attribute(jsx_attribute); + } + JSXAttrOrSpread::SpreadElement(_spread_element) => { + unimplemented!("JSXAttrOrSpread::SpreadElement") + } + } + } + + fn convert_jsx_attribute_value(&mut self, jsx_attribute_value: &JSXAttrValue) { + match jsx_attribute_value { + JSXAttrValue::Lit(literal) => self.convert_literal(literal), + JSXAttrValue::JSXExprContainer(expression_container) => { + self.convert_jsx_expression_container(expression_container) + } + JSXAttrValue::JSXElement(jsx_element) => self.convert_jsx_element(jsx_element), + JSXAttrValue::JSXFragment(jsx_fragment) => self.convert_jsx_fragment(jsx_fragment), + } + } + + fn convert_jsx_element_child(&mut self, jsx_element_child: &JSXElementChild) { + match jsx_element_child { + JSXElementChild::JSXText(jsx_text) => { + self.convert_jsx_text(jsx_text); + } + JSXElementChild::JSXExprContainer(jsx_expr_container) => { + self.convert_jsx_expression_container(jsx_expr_container); + } + JSXElementChild::JSXSpreadChild(_jsx_spread_child) => { + unimplemented!("JSXElementChild::JSXSpreadChild") + } + JSXElementChild::JSXFragment(jsx_fragment) => { + self.convert_jsx_fragment(jsx_fragment); + } + JSXElementChild::JSXElement(jsx_element) => { + self.convert_jsx_element(jsx_element); + } + } + } + + fn convert_jsx_element_name(&mut self, jsx_element_name: &JSXElementName) { + match jsx_element_name { + JSXElementName::Ident(identifier) => self.store_jsx_identifier(identifier), + JSXElementName::JSXMemberExpr(_jsx_member_expression) => { + unimplemented!("JSXElementName::JSXMemberExpr") + } + JSXElementName::JSXNamespacedName(_jsx_namespaced_name) => { + unimplemented!("JSXElementName::JSXNamespacedName") + } + } + } + fn convert_literal(&mut self, literal: &Lit) { match literal { Lit::BigInt(bigint_literal) => self.store_literal_bigint(bigint_literal), @@ -677,15 +742,48 @@ impl<'a> AstConverter<'a> { } } - fn convert_jsx_attribute_value(&mut self, jsx_attribute_value: &JSXAttrValue) { - match jsx_attribute_value { - JSXAttrValue::Lit(literal) => self.convert_literal(literal), - JSXAttrValue::JSXExprContainer(expression_container) => { - self.convert_jsx_expression_container(expression_container) - } - JSXAttrValue::JSXElement(jsx_element) => self.convert_jsx_element(jsx_element), - JSXAttrValue::JSXFragment(jsx_fragment) => self.convert_jsx_fragment(jsx_fragment), - } + fn convert_jsx_attribute(&mut self, jsx_attribute: &JSXAttr) { + let end_position = self.add_type_and_start( + &TYPE_JSX_ATTRIBUTE, + &jsx_attribute.span, + JSX_ATTRIBUTE_RESERVED_BYTES, + false, + ); + // name + self.update_reference_position(end_position + JSX_ATTRIBUTE_NAME_OFFSET); + self.convert_jsx_attribute_name(&jsx_attribute.name); + // value + if let Some(jsx_attribute_value) = jsx_attribute.value.as_ref() { + self.update_reference_position(end_position + JSX_ATTRIBUTE_VALUE_OFFSET); + self.convert_jsx_attribute_value(jsx_attribute_value); + }; + // end + self.add_end(end_position, &jsx_attribute.span); + } + + fn convert_jsx_closing_element(&mut self, jsx_closing_element: &JSXClosingElement) { + let end_position = self.add_type_and_start( + &TYPE_JSX_CLOSING_ELEMENT, + &jsx_closing_element.span, + JSX_CLOSING_ELEMENT_RESERVED_BYTES, + false, + ); + // name + self.update_reference_position(end_position + JSX_CLOSING_ELEMENT_NAME_OFFSET); + self.convert_jsx_element_name(&jsx_closing_element.name); + // end + self.add_end(end_position, &jsx_closing_element.span); + } + + fn convert_jsx_closing_fragment(&mut self, jsx_closing_fragment: &JSXClosingFragment) { + let end_position = self.add_type_and_start( + &TYPE_JSX_CLOSING_FRAGMENT, + &jsx_closing_fragment.span, + JSX_CLOSING_FRAGMENT_RESERVED_BYTES, + false, + ); + // end + self.add_end(end_position, &jsx_closing_fragment.span); } fn convert_jsx_element(&mut self, jsx_element: &JSXElement) { @@ -697,7 +795,7 @@ impl<'a> AstConverter<'a> { ); // openingElement self.update_reference_position(end_position + JSX_ELEMENT_OPENING_ELEMENT_OFFSET); - self.store_jsx_opening_element(&jsx_element.opening); + self.convert_jsx_opening_element(&jsx_element.opening); // children self.convert_item_list( &jsx_element.children, @@ -716,25 +814,15 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &jsx_element.span); } - fn convert_jsx_element_child(&mut self, jsx_element_child: &JSXElementChild) { - match jsx_element_child { - JSXElementChild::JSXText(jsx_text) => { - self.store_jsx_text(jsx_text); - } - JSXElementChild::JSXExprContainer(jsx_expr_container) => { - self.convert_jsx_expression_container(jsx_expr_container); - } - JSXElementChild::JSXSpreadChild(_jsx_spread_child) => { - // self.store_jsx_spread_child(jsx_spread_child); - unimplemented!("JSXElementChild::JSXSpreadChild") - } - JSXElementChild::JSXFragment(jsx_fragment) => { - self.convert_jsx_fragment(jsx_fragment); - } - JSXElementChild::JSXElement(jsx_element) => { - self.convert_jsx_element(jsx_element); - } - } + fn convert_jsx_empty_expression(&mut self, jsx_empty_expression: &JSXEmptyExpr) { + let end_position = self.add_type_and_start( + &TYPE_JSX_EMPTY_EXPRESSION, + &jsx_empty_expression.span, + JSX_EMPTY_EXPRESSION_RESERVED_BYTES, + false, + ); + // end + self.add_end(end_position, &jsx_empty_expression.span); } fn convert_jsx_expression_container(&mut self, jsx_expr_container: &JSXExprContainer) { @@ -751,40 +839,54 @@ impl<'a> AstConverter<'a> { self.convert_expression(expression); } JSXExpr::JSXEmptyExpr(jsx_empty_expr) => { - self.store_jsx_empty_expr(jsx_empty_expr); + self.convert_jsx_empty_expression(jsx_empty_expr); } } // end self.add_end(end_position, &jsx_expr_container.span); } - fn store_jsx_empty_expr(&mut self, jsx_empty_expr: &JSXEmptyExpr) { + fn convert_jsx_fragment(&mut self, jsx_fragment: &JSXFragment) { let end_position = self.add_type_and_start( - &TYPE_JSX_EMPTY_EXPRESSION, - &jsx_empty_expr.span, - JSX_EMPTY_EXPRESSION_RESERVED_BYTES, + &TYPE_JSX_FRAGMENT, + &jsx_fragment.span, + JSX_FRAGMENT_RESERVED_BYTES, false, ); + // openingFragment + self.update_reference_position(end_position + JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET); + self.convert_jsx_opening_fragment(jsx_fragment.opening); + // children + self.convert_item_list( + &jsx_fragment.children, + end_position + JSX_FRAGMENT_CHILDREN_OFFSET, + |_ast_converter, _jsx_fragment_child| { + unimplemented!("Convert JSXFragmentChild"); + // ast_converter.convert_jsx_fragment_child(jsx_fragment_child); + // true + }, + ); + // closingFragment + self.update_reference_position(end_position + JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET); + self.convert_jsx_closing_fragment(&jsx_fragment.closing); // end - self.add_end(end_position, &jsx_empty_expr.span); + self.add_end(end_position, &jsx_fragment.span); } - fn store_jsx_text(&mut self, jsx_text: &JSXText) { + fn store_jsx_identifier(&mut self, span: &Span, name: &str) { let end_position = self.add_type_and_start( - &TYPE_JSX_TEXT, - &jsx_text.span, - JSX_TEXT_RESERVED_BYTES, + &TYPE_JSX_IDENTIFIER, + span, + JSX_IDENTIFIER_RESERVED_BYTES, false, ); - // value - self.convert_string(&jsx_text.value, end_position + JSX_TEXT_VALUE_OFFSET); - // raw - self.convert_string(&jsx_text.raw, end_position + JSX_TEXT_RAW_OFFSET); + // name + self.convert_string(name, end_position + JSX_IDENTIFIER_NAME_OFFSET); // end - self.add_end(end_position, &jsx_text.span); + self.add_end(end_position, span); } - fn store_jsx_opening_element(&mut self, jsx_opening_element: &JSXOpeningElement) { + fn convert_jsx_opening_element(&mut self, jsx_opening_element: &JSXOpeningElement) { let end_position = self.add_type_and_start( &TYPE_JSX_OPENING_ELEMENT, &jsx_opening_element.span, @@ -813,116 +915,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &jsx_opening_element.span); } - fn convert_jsx_closing_element(&mut self, jsx_closing_element: &JSXClosingElement) { - let end_position = self.add_type_and_start( - &TYPE_JSX_CLOSING_ELEMENT, - &jsx_closing_element.span, - JSX_CLOSING_ELEMENT_RESERVED_BYTES, - false, - ); - // name - self.update_reference_position(end_position + JSX_CLOSING_ELEMENT_NAME_OFFSET); - self.convert_jsx_element_name(&jsx_closing_element.name); - // end - self.add_end(end_position, &jsx_closing_element.span); - } - - fn convert_jsx_element_name(&mut self, jsx_element_name: &JSXElementName) { - match jsx_element_name { - JSXElementName::Ident(identifier) => { - self.store_jsx_identifier(&identifier.span, &identifier.sym) - } - JSXElementName::JSXMemberExpr(jsx_member_expr) => { - unimplemented!("JSXElementName::JSXMemberExpr") - } - JSXElementName::JSXNamespacedName(jsx_namespaced_name) => { - unimplemented!("JSXElementName::JSXNamespacedName") - } - } - } - - fn convert_jsx_attribute_or_spread(&mut self, jsx_attribute: &JSXAttrOrSpread) { - match jsx_attribute { - JSXAttrOrSpread::JSXAttr(jsx_attribute) => { - self.store_jsx_attribute(jsx_attribute); - } - JSXAttrOrSpread::SpreadElement(spread_element) => { - unimplemented!("JSXAttrOrSpread::SpreadElement") - } - } - } - - fn store_jsx_attribute(&mut self, jsx_attribute: &JSXAttr) { - let end_position = self.add_type_and_start( - &TYPE_JSX_ATTRIBUTE, - &jsx_attribute.span, - JSX_ATTRIBUTE_RESERVED_BYTES, - false, - ); - // name - self.update_reference_position(end_position + JSX_ATTRIBUTE_NAME_OFFSET); - self.convert_jsx_attribute_name(&jsx_attribute.name); - // value - if let Some(jsx_attribute_value) = jsx_attribute.value.as_ref() { - self.update_reference_position(end_position + JSX_ATTRIBUTE_VALUE_OFFSET); - self.convert_jsx_attribute_value(jsx_attribute_value); - }; - // end - self.add_end(end_position, &jsx_attribute.span); - } - - fn convert_jsx_attribute_name(&mut self, jsx_attribute_name: &JSXAttrName) { - match jsx_attribute_name { - JSXAttrName::Ident(identifier) => { - self.store_jsx_identifier(&identifier.span, &identifier.sym); - } - JSXAttrName::JSXNamespacedName(jsx_namespaced_name) => { - unimplemented!("JSXElementName::JSXNamespacedName") - } - } - } - - fn store_jsx_identifier(&mut self, span: &Span, name: &str) { - let end_position = self.add_type_and_start( - &TYPE_JSX_IDENTIFIER, - span, - JSX_IDENTIFIER_RESERVED_BYTES, - false, - ); - // name - self.convert_string(name, end_position + JSX_IDENTIFIER_NAME_OFFSET); - // end - self.add_end(end_position, span); - } - - fn convert_jsx_fragment(&mut self, jsx_fragment: &JSXFragment) { - let end_position = self.add_type_and_start( - &TYPE_JSX_FRAGMENT, - &jsx_fragment.span, - JSX_FRAGMENT_RESERVED_BYTES, - false, - ); - // openingFragment - self.update_reference_position(end_position + JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET); - self.store_jsx_opening_fragment(jsx_fragment.opening); - // children - self.convert_item_list( - &jsx_fragment.children, - end_position + JSX_FRAGMENT_CHILDREN_OFFSET, - |ast_converter, jsx_fragment_child| { - unimplemented!("Convert JSXFragmentChild"); - // ast_converter.convert_jsx_fragment_child(jsx_fragment_child); - // true - }, - ); - // closingFragment - self.update_reference_position(end_position + JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET); - self.store_jsx_closing_fragment(&jsx_fragment.closing); - // end - self.add_end(end_position, &jsx_fragment.span); - } - - fn store_jsx_opening_fragment(&mut self, jsxopening_fragment: JSXOpeningFragment) { + fn convert_jsx_opening_fragment(&mut self, jsxopening_fragment: JSXOpeningFragment) { let end_position = self.add_type_and_start( &TYPE_JSX_OPENING_FRAGMENT, &jsxopening_fragment.span, @@ -933,16 +926,21 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &jsxopening_fragment.span); } - fn store_jsx_closing_fragment(&mut self, jsx_closing_fragment: &JSXClosingFragment) { + fn convert_jsx_text(&mut self, jsx_text: &JSXText) { let end_position = self.add_type_and_start( - &TYPE_JSX_CLOSING_FRAGMENT, - &jsx_closing_fragment.span, - JSX_CLOSING_FRAGMENT_RESERVED_BYTES, + &TYPE_JSX_TEXT, + &jsx_text.span, + JSX_TEXT_RESERVED_BYTES, false, ); + // value + self.convert_string(&jsx_text.value, end_position + JSX_TEXT_VALUE_OFFSET); + // raw + self.convert_string(&jsx_text.raw, end_position + JSX_TEXT_RAW_OFFSET); // end - self.add_end(end_position, &jsx_closing_fragment.span); + self.add_end(end_position, &jsx_text.span); } + } pub fn convert_annotation(buffer: &mut Vec, annotation: &ConvertedAnnotation) { From da70cc55ba88e56dd949949539032f343c727526 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 29 Apr 2024 06:38:06 +0200 Subject: [PATCH 13/62] Associate identifier with variable --- src/ast/nodes/Identifier.ts | 248 +----------------- src/ast/nodes/JSXIdentifier.ts | 45 +++- src/ast/nodes/shared/IdentifierBase.ts | 243 +++++++++++++++++ src/ast/variables/ExportDefaultVariable.ts | 3 +- src/ast/variables/ExternalVariable.ts | 4 +- src/ast/variables/NamespaceVariable.ts | 6 +- src/ast/variables/Variable.ts | 12 +- .../jsx/preserves-jsx-child/_expected.js | 3 +- .../samples/jsx/preserves-jsx-child/main.js | 2 - .../jsx/preserves-jsx-closing/_expected.js | 3 +- .../samples/jsx/preserves-jsx-closing/main.js | 2 - .../_expected.js | 3 +- .../preserves-jsx-empty-expression/main.js | 2 - .../_expected.js | 3 +- .../main.js | 2 - .../jsx/preserves-jsx-fragment/_expected.js | 3 +- .../jsx/preserves-jsx-fragment/main.js | 2 - .../jsx/preserves-jsx-text/_expected.js | 3 +- .../samples/jsx/preserves-jsx-text/main.js | 2 - .../_expected.js | 3 +- .../jsx/preserves-jsx-with-attributes/main.js | 2 - .../samples/jsx/preserves-jsx/_expected.js | 3 +- .../samples/jsx/transpiles-react/_expected.js | 4 +- 23 files changed, 318 insertions(+), 285 deletions(-) create mode 100644 src/ast/nodes/shared/IdentifierBase.ts diff --git a/src/ast/nodes/Identifier.ts b/src/ast/nodes/Identifier.ts index 771526ef80a..c513e800b9f 100644 --- a/src/ast/nodes/Identifier.ts +++ b/src/ast/nodes/Identifier.ts @@ -1,57 +1,23 @@ import isReference, { type NodeWithFieldDefinition } from 'is-reference'; import type MagicString from 'magic-string'; -import type { NormalizedTreeshakingOptions } from '../../rollup/types'; import { BLANK } from '../../utils/blank'; -import { logIllegalImportReassignment } from '../../utils/logs'; -import { PureFunctionKey } from '../../utils/pureFunctions'; import type { NodeRenderOptions, RenderOptions } from '../../utils/renderHelpers'; -import { markModuleAndImpureDependenciesAsExecuted } from '../../utils/traverseStaticDependencies'; -import type { DeoptimizableEntity } from '../DeoptimizableEntity'; -import type { HasEffectsContext, InclusionContext } from '../ExecutionContext'; -import type { NodeInteraction, NodeInteractionCalled } from '../NodeInteractions'; -import { - INTERACTION_ACCESSED, - INTERACTION_ASSIGNED, - INTERACTION_CALLED, - NODE_INTERACTION_UNKNOWN_ACCESS -} from '../NodeInteractions'; import type FunctionScope from '../scopes/FunctionScope'; -import { EMPTY_PATH, type ObjectPath, type PathTracker } from '../utils/PathTracker'; -import GlobalVariable from '../variables/GlobalVariable'; -import LocalVariable from '../variables/LocalVariable'; +import type LocalVariable from '../variables/LocalVariable'; import type Variable from '../variables/Variable'; import * as NodeType from './NodeType'; -import { Flag, isFlagSet, setFlag } from './shared/BitFlags'; -import { - type ExpressionEntity, - type LiteralValueOrUnknown, - UNKNOWN_EXPRESSION -} from './shared/Expression'; -import { NodeBase } from './shared/Node'; +import { type ExpressionEntity } from './shared/Expression'; +import IdentifierBase from './shared/IdentifierBase'; import type { PatternNode } from './shared/Pattern'; import type { VariableKind } from './shared/VariableKinds'; -import type SpreadElement from './SpreadElement'; export type IdentifierWithVariable = Identifier & { variable: Variable }; -const tdzVariableKinds = new Set(['class', 'const', 'let', 'var', 'using', 'await using']); - -export default class Identifier extends NodeBase implements PatternNode { - declare name: string; - declare type: NodeType.tIdentifier; +export default class Identifier extends IdentifierBase implements PatternNode { + name!: string; + type!: NodeType.tIdentifier; variable: Variable | null = null; - private get isTDZAccess(): boolean | null { - if (!isFlagSet(this.flags, Flag.tdzAccessDefined)) { - return null; - } - return isFlagSet(this.flags, Flag.tdzAccess); - } - private set isTDZAccess(value: boolean) { - this.flags = setFlag(this.flags, Flag.tdzAccessDefined, true); - this.flags = setFlag(this.flags, Flag.tdzAccess, value); - } - addExportedVariables( variables: Variable[], exportNamesByVariable: ReadonlyMap @@ -61,12 +27,11 @@ export default class Identifier extends NodeBase implements PatternNode { } } - private isReferenceVariable = false; bind(): void { if (!this.variable && isReference(this, this.parent as NodeWithFieldDefinition)) { this.variable = this.scope.findVariable(this.name); this.variable.addReference(this); - this.isReferenceVariable = true; + this.isVariableReference = true; } } @@ -108,150 +73,6 @@ export default class Identifier extends NodeBase implements PatternNode { return [(this.variable = variable)]; } - deoptimizeArgumentsOnInteractionAtPath( - interaction: NodeInteraction, - path: ObjectPath, - recursionTracker: PathTracker - ): void { - this.variable!.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker); - } - - deoptimizePath(path: ObjectPath): void { - if (path.length === 0 && !this.scope.contains(this.name)) { - this.disallowImportReassignment(); - } - // We keep conditional chaining because an unknown Node could have an - // Identifier as property that might be deoptimized by default - this.variable?.deoptimizePath(path); - } - - getLiteralValueAtPath( - path: ObjectPath, - recursionTracker: PathTracker, - origin: DeoptimizableEntity - ): LiteralValueOrUnknown { - return this.getVariableRespectingTDZ()!.getLiteralValueAtPath(path, recursionTracker, origin); - } - - getReturnExpressionWhenCalledAtPath( - path: ObjectPath, - interaction: NodeInteractionCalled, - recursionTracker: PathTracker, - origin: DeoptimizableEntity - ): [expression: ExpressionEntity, isPure: boolean] { - const [expression, isPure] = - this.getVariableRespectingTDZ()!.getReturnExpressionWhenCalledAtPath( - path, - interaction, - recursionTracker, - origin - ); - return [expression, isPure || this.isPureFunction(path)]; - } - - hasEffects(context: HasEffectsContext): boolean { - if (!this.deoptimized) this.applyDeoptimizations(); - if (this.isPossibleTDZ() && this.variable!.kind !== 'var') { - return true; - } - return ( - (this.scope.context.options.treeshake as NormalizedTreeshakingOptions) - .unknownGlobalSideEffects && - this.variable instanceof GlobalVariable && - !this.isPureFunction(EMPTY_PATH) && - this.variable.hasEffectsOnInteractionAtPath( - EMPTY_PATH, - NODE_INTERACTION_UNKNOWN_ACCESS, - context - ) - ); - } - - hasEffectsOnInteractionAtPath( - path: ObjectPath, - interaction: NodeInteraction, - context: HasEffectsContext - ): boolean { - switch (interaction.type) { - case INTERACTION_ACCESSED: { - return ( - this.variable !== null && - !this.isPureFunction(path) && - this.getVariableRespectingTDZ()!.hasEffectsOnInteractionAtPath(path, interaction, context) - ); - } - case INTERACTION_ASSIGNED: { - return ( - path.length > 0 ? this.getVariableRespectingTDZ() : this.variable - )!.hasEffectsOnInteractionAtPath(path, interaction, context); - } - case INTERACTION_CALLED: { - return ( - !this.isPureFunction(path) && - this.getVariableRespectingTDZ()!.hasEffectsOnInteractionAtPath(path, interaction, context) - ); - } - } - } - - include(): void { - if (!this.deoptimized) this.applyDeoptimizations(); - if (!this.included) { - this.included = true; - if (this.variable !== null) { - this.scope.context.includeVariableInModule(this.variable); - } - } - } - - includeCallArguments( - context: InclusionContext, - parameters: readonly (ExpressionEntity | SpreadElement)[] - ): void { - this.variable!.includeCallArguments(context, parameters); - } - - isPossibleTDZ(): boolean { - // return cached value to avoid issues with the next tree-shaking pass - const cachedTdzAccess = this.isTDZAccess; - if (cachedTdzAccess !== null) return cachedTdzAccess; - - if ( - !( - this.variable instanceof LocalVariable && - this.variable.kind && - tdzVariableKinds.has(this.variable.kind) && - // We ignore modules that did not receive a treeshaking pass yet as that - // causes many false positives due to circular dependencies or disabled - // moduleSideEffects. - this.variable.module.hasTreeShakingPassStarted - ) - ) { - return (this.isTDZAccess = false); - } - - let decl_id; - if ( - this.variable.declarations && - this.variable.declarations.length === 1 && - (decl_id = this.variable.declarations[0] as any) && - this.start < decl_id.start && - closestParentFunctionOrProgram(this) === closestParentFunctionOrProgram(decl_id) - ) { - // a variable accessed before its declaration - // in the same function or at top level of module - return (this.isTDZAccess = true); - } - - if (!this.variable.initReached) { - // Either a const/let TDZ violation or - // var use before declaration was encountered. - return (this.isTDZAccess = true); - } - - return (this.isTDZAccess = false); - } - markDeclarationReached(): void { this.variable!.initReached = true; } @@ -283,59 +104,4 @@ export default class Identifier extends NodeBase implements PatternNode { } } } - - private disallowImportReassignment(): never { - return this.scope.context.error( - logIllegalImportReassignment(this.name, this.scope.context.module.id), - this.start - ); - } - - protected applyDeoptimizations(): void { - this.deoptimized = true; - if (this.variable instanceof LocalVariable) { - // When accessing a variable from a module without side effects, this - // means we use an export of that module and therefore need to potentially - // include it in the bundle. - if (!this.variable.module.isExecuted) { - markModuleAndImpureDependenciesAsExecuted(this.variable.module); - } - this.variable.consolidateInitializers(); - this.scope.context.requestTreeshakingPass(); - } - if (this.isReferenceVariable) { - this.variable!.addUsedPlace(this); - this.scope.context.requestTreeshakingPass(); - } - } - - private getVariableRespectingTDZ(): ExpressionEntity | null { - if (this.isPossibleTDZ()) { - return UNKNOWN_EXPRESSION; - } - return this.variable; - } - - private isPureFunction(path: ObjectPath) { - let currentPureFunction = this.scope.context.manualPureFunctions[this.name]; - for (const segment of path) { - if (currentPureFunction) { - if (currentPureFunction[PureFunctionKey]) { - return true; - } - currentPureFunction = currentPureFunction[segment as string]; - } else { - return false; - } - } - return currentPureFunction?.[PureFunctionKey] as boolean; - } -} - -function closestParentFunctionOrProgram(node: any): any { - while (node && !/^Program|Function/.test(node.type)) { - node = node.parent; - } - // one of: ArrowFunctionExpression, FunctionDeclaration, FunctionExpression or Program - return node; } diff --git a/src/ast/nodes/JSXIdentifier.ts b/src/ast/nodes/JSXIdentifier.ts index 5277e778297..8cc701e132d 100644 --- a/src/ast/nodes/JSXIdentifier.ts +++ b/src/ast/nodes/JSXIdentifier.ts @@ -1,7 +1,48 @@ +import type MagicString from 'magic-string'; +import type { RenderOptions } from '../../utils/renderHelpers'; +import type JSXOpeningElement from './JSXOpeningElement'; import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; +import IdentifierBase from './shared/IdentifierBase'; -export default class JSXIdentifier extends NodeBase { +export default class JSXIdentifier extends IdentifierBase { type!: NodeType.tJSXIdentifier; name!: string; + + bind(): void { + if (this.isReference()) { + this.variable = this.scope.findVariable(this.name); + this.variable.addReference(this); + } + } + + render( + code: MagicString, + { snippets: { getPropertyAccess }, useOriginalName }: RenderOptions + ): void { + if (this.variable) { + const name = this.variable.getName(getPropertyAccess, useOriginalName); + + if (name !== this.name) { + code.overwrite(this.start, this.end, name, { + contentOnly: true, + storeName: true + }); + } + } + } + + private isReference(): boolean { + switch (this.parent.type) { + case 'JSXOpeningElement': + case 'JSXClosingElement': { + return (this.parent as JSXOpeningElement).name === this; + } + case 'JSXAttribute': { + return false; + } + default: { + throw new Error(`Unexpected parent node type for JSXIdentifier: ${this.parent.type}`); + } + } + } } diff --git a/src/ast/nodes/shared/IdentifierBase.ts b/src/ast/nodes/shared/IdentifierBase.ts new file mode 100644 index 00000000000..684d7f2de81 --- /dev/null +++ b/src/ast/nodes/shared/IdentifierBase.ts @@ -0,0 +1,243 @@ +import type { NormalizedTreeshakingOptions } from '../../../rollup/types'; +import { logIllegalImportReassignment } from '../../../utils/logs'; +import { PureFunctionKey } from '../../../utils/pureFunctions'; +import { markModuleAndImpureDependenciesAsExecuted } from '../../../utils/traverseStaticDependencies'; +import type { DeoptimizableEntity } from '../../DeoptimizableEntity'; +import type { HasEffectsContext, InclusionContext } from '../../ExecutionContext'; +import type { NodeInteraction, NodeInteractionCalled } from '../../NodeInteractions'; +import { + INTERACTION_ACCESSED, + INTERACTION_ASSIGNED, + INTERACTION_CALLED, + NODE_INTERACTION_UNKNOWN_ACCESS +} from '../../NodeInteractions'; +import type { ObjectPath, PathTracker } from '../../utils/PathTracker'; +import { EMPTY_PATH } from '../../utils/PathTracker'; +import GlobalVariable from '../../variables/GlobalVariable'; +import LocalVariable from '../../variables/LocalVariable'; +import type Variable from '../../variables/Variable'; +import type SpreadElement from '../SpreadElement'; +import { Flag, isFlagSet, setFlag } from './BitFlags'; +import type { ExpressionEntity, LiteralValueOrUnknown } from './Expression'; +import { UNKNOWN_EXPRESSION } from './Expression'; +import { NodeBase } from './Node'; + +const tdzVariableKinds = new Set(['class', 'const', 'let', 'var', 'using', 'await using']); + +export default class IdentifierBase extends NodeBase { + name!: string; + variable: Variable | null = null; + + protected isVariableReference = false; + + private get isTDZAccess(): boolean | null { + if (!isFlagSet(this.flags, Flag.tdzAccessDefined)) { + return null; + } + return isFlagSet(this.flags, Flag.tdzAccess); + } + + private set isTDZAccess(value: boolean) { + this.flags = setFlag(this.flags, Flag.tdzAccessDefined, true); + this.flags = setFlag(this.flags, Flag.tdzAccess, value); + } + + deoptimizeArgumentsOnInteractionAtPath( + interaction: NodeInteraction, + path: ObjectPath, + recursionTracker: PathTracker + ): void { + this.variable!.deoptimizeArgumentsOnInteractionAtPath(interaction, path, recursionTracker); + } + + deoptimizePath(path: ObjectPath): void { + if (path.length === 0 && !this.scope.contains(this.name)) { + this.disallowImportReassignment(); + } + // We keep conditional chaining because an unknown Node could have an + // Identifier as property that might be deoptimized by default + this.variable?.deoptimizePath(path); + } + + getLiteralValueAtPath( + path: ObjectPath, + recursionTracker: PathTracker, + origin: DeoptimizableEntity + ): LiteralValueOrUnknown { + return this.getVariableRespectingTDZ()!.getLiteralValueAtPath(path, recursionTracker, origin); + } + + getReturnExpressionWhenCalledAtPath( + path: ObjectPath, + interaction: NodeInteractionCalled, + recursionTracker: PathTracker, + origin: DeoptimizableEntity + ): [expression: ExpressionEntity, isPure: boolean] { + const [expression, isPure] = + this.getVariableRespectingTDZ()!.getReturnExpressionWhenCalledAtPath( + path, + interaction, + recursionTracker, + origin + ); + return [expression, isPure || this.isPureFunction(path)]; + } + + hasEffects(context: HasEffectsContext): boolean { + if (!this.deoptimized) this.applyDeoptimizations(); + if (this.isPossibleTDZ() && this.variable!.kind !== 'var') { + return true; + } + return ( + (this.scope.context.options.treeshake as NormalizedTreeshakingOptions) + .unknownGlobalSideEffects && + this.variable instanceof GlobalVariable && + !this.isPureFunction(EMPTY_PATH) && + this.variable.hasEffectsOnInteractionAtPath( + EMPTY_PATH, + NODE_INTERACTION_UNKNOWN_ACCESS, + context + ) + ); + } + + hasEffectsOnInteractionAtPath( + path: ObjectPath, + interaction: NodeInteraction, + context: HasEffectsContext + ): boolean { + switch (interaction.type) { + case INTERACTION_ACCESSED: { + return ( + this.variable !== null && + !this.isPureFunction(path) && + this.getVariableRespectingTDZ()!.hasEffectsOnInteractionAtPath(path, interaction, context) + ); + } + case INTERACTION_ASSIGNED: { + return ( + path.length > 0 ? this.getVariableRespectingTDZ() : this.variable + )!.hasEffectsOnInteractionAtPath(path, interaction, context); + } + case INTERACTION_CALLED: { + return ( + !this.isPureFunction(path) && + this.getVariableRespectingTDZ()!.hasEffectsOnInteractionAtPath(path, interaction, context) + ); + } + } + } + + include(): void { + if (!this.deoptimized) this.applyDeoptimizations(); + if (!this.included) { + this.included = true; + if (this.variable !== null) { + this.scope.context.includeVariableInModule(this.variable); + } + } + } + + includeCallArguments( + context: InclusionContext, + parameters: readonly (ExpressionEntity | SpreadElement)[] + ): void { + this.variable!.includeCallArguments(context, parameters); + } + + isPossibleTDZ(): boolean { + // return cached value to avoid issues with the next tree-shaking pass + const cachedTdzAccess = this.isTDZAccess; + if (cachedTdzAccess !== null) return cachedTdzAccess; + + if ( + !( + this.variable instanceof LocalVariable && + this.variable.kind && + tdzVariableKinds.has(this.variable.kind) && + // We ignore modules that did not receive a treeshaking pass yet as that + // causes many false positives due to circular dependencies or disabled + // moduleSideEffects. + this.variable.module.hasTreeShakingPassStarted + ) + ) { + return (this.isTDZAccess = false); + } + + let decl_id; + if ( + this.variable.declarations && + this.variable.declarations.length === 1 && + (decl_id = this.variable.declarations[0] as any) && + this.start < decl_id.start && + closestParentFunctionOrProgram(this) === closestParentFunctionOrProgram(decl_id) + ) { + // a variable accessed before its declaration + // in the same function or at top level of module + return (this.isTDZAccess = true); + } + + if (!this.variable.initReached) { + // Either a const/let TDZ violation or + // var use before declaration was encountered. + return (this.isTDZAccess = true); + } + + return (this.isTDZAccess = false); + } + + protected applyDeoptimizations(): void { + this.deoptimized = true; + if (this.variable instanceof LocalVariable) { + // When accessing a variable from a module without side effects, this + // means we use an export of that module and therefore need to potentially + // include it in the bundle. + if (!this.variable.module.isExecuted) { + markModuleAndImpureDependenciesAsExecuted(this.variable.module); + } + this.variable.consolidateInitializers(); + this.scope.context.requestTreeshakingPass(); + } + if (this.isVariableReference) { + this.variable!.addUsedPlace(this); + this.scope.context.requestTreeshakingPass(); + } + } + + private disallowImportReassignment(): never { + return this.scope.context.error( + logIllegalImportReassignment(this.name, this.scope.context.module.id), + this.start + ); + } + + private getVariableRespectingTDZ(): ExpressionEntity | null { + if (this.isPossibleTDZ()) { + return UNKNOWN_EXPRESSION; + } + return this.variable; + } + + private isPureFunction(path: ObjectPath) { + let currentPureFunction = this.scope.context.manualPureFunctions[this.name]; + for (const segment of path) { + if (currentPureFunction) { + if (currentPureFunction[PureFunctionKey]) { + return true; + } + currentPureFunction = currentPureFunction[segment as string]; + } else { + return false; + } + } + return currentPureFunction?.[PureFunctionKey] as boolean; + } +} + +function closestParentFunctionOrProgram(node: any): any { + while (node && !/^Program|Function/.test(node.type)) { + node = node.parent; + } + // one of: ArrowFunctionExpression, FunctionDeclaration, FunctionExpression or Program + return node; +} diff --git a/src/ast/variables/ExportDefaultVariable.ts b/src/ast/variables/ExportDefaultVariable.ts index 70810936e5a..baed0873c12 100644 --- a/src/ast/variables/ExportDefaultVariable.ts +++ b/src/ast/variables/ExportDefaultVariable.ts @@ -3,6 +3,7 @@ import ClassDeclaration from '../nodes/ClassDeclaration'; import type ExportDefaultDeclaration from '../nodes/ExportDefaultDeclaration'; import FunctionDeclaration from '../nodes/FunctionDeclaration'; import Identifier, { type IdentifierWithVariable } from '../nodes/Identifier'; +import type IdentifierBase from '../nodes/shared/IdentifierBase'; import type { NodeBase } from '../nodes/shared/Node'; import LocalVariable from './LocalVariable'; import UndefinedVariable from './UndefinedVariable'; @@ -32,7 +33,7 @@ export default class ExportDefaultVariable extends LocalVariable { } } - addReference(identifier: Identifier): void { + addReference(identifier: IdentifierBase): void { if (!this.hasId) { this.name = identifier.name; } diff --git a/src/ast/variables/ExternalVariable.ts b/src/ast/variables/ExternalVariable.ts index 529802a7ce7..0775fc03682 100644 --- a/src/ast/variables/ExternalVariable.ts +++ b/src/ast/variables/ExternalVariable.ts @@ -1,7 +1,7 @@ import type ExternalModule from '../../ExternalModule'; import type { NodeInteraction } from '../NodeInteractions'; import { INTERACTION_ACCESSED } from '../NodeInteractions'; -import type Identifier from '../nodes/Identifier'; +import type IdentifierBase from '../nodes/shared/IdentifierBase'; import type { ObjectPath } from '../utils/PathTracker'; import Variable from './Variable'; @@ -16,7 +16,7 @@ export default class ExternalVariable extends Variable { this.isNamespace = name === '*'; } - addReference(identifier: Identifier): void { + addReference(identifier: IdentifierBase): void { this.referenced = true; if (this.name === 'default' || this.name === '*') { this.module.suggestName(identifier.name); diff --git a/src/ast/variables/NamespaceVariable.ts b/src/ast/variables/NamespaceVariable.ts index dc5efceea89..6085c435b76 100644 --- a/src/ast/variables/NamespaceVariable.ts +++ b/src/ast/variables/NamespaceVariable.ts @@ -6,9 +6,9 @@ import { getSystemExportStatement } from '../../utils/systemJsRendering'; import type { HasEffectsContext } from '../ExecutionContext'; import type { NodeInteraction } from '../NodeInteractions'; import { INTERACTION_ASSIGNED, INTERACTION_CALLED } from '../NodeInteractions'; -import type Identifier from '../nodes/Identifier'; import type { LiteralValueOrUnknown } from '../nodes/shared/Expression'; import { deoptimizeInteraction, UnknownValue } from '../nodes/shared/Expression'; +import type IdentifierBase from '../nodes/shared/IdentifierBase'; import type ChildScope from '../scopes/ChildScope'; import type { ObjectPath, PathTracker } from '../utils/PathTracker'; import { SymbolToStringTag } from '../utils/PathTracker'; @@ -22,7 +22,7 @@ export default class NamespaceVariable extends Variable { private memberVariables: Record | null = null; private mergedNamespaces: readonly Variable[] = []; private referencedEarly = false; - private references: Identifier[] = []; + private references: IdentifierBase[] = []; constructor(context: AstContext) { super(context.getModuleName()); @@ -30,7 +30,7 @@ export default class NamespaceVariable extends Variable { this.module = context.module; } - addReference(identifier: Identifier): void { + addReference(identifier: IdentifierBase): void { this.references.push(identifier); this.name = identifier.name; } diff --git a/src/ast/variables/Variable.ts b/src/ast/variables/Variable.ts index 0cd2e40dddb..f77ce67fd04 100644 --- a/src/ast/variables/Variable.ts +++ b/src/ast/variables/Variable.ts @@ -5,9 +5,9 @@ import type { HasEffectsContext } from '../ExecutionContext'; import type { NodeInteraction } from '../NodeInteractions'; import { INTERACTION_ACCESSED } from '../NodeInteractions'; import type CallExpression from '../nodes/CallExpression'; -import type Identifier from '../nodes/Identifier'; import * as NodeType from '../nodes/NodeType'; import { ExpressionEntity } from '../nodes/shared/Expression'; +import type IdentifierBase from '../nodes/shared/IdentifierBase'; import type { NodeBase } from '../nodes/shared/Node'; import type { VariableKind } from '../nodes/shared/VariableKinds'; import type { ObjectPath } from '../utils/PathTracker'; @@ -39,7 +39,7 @@ export default class Variable extends ExpressionEntity { * Binds identifiers that reference this variable to this variable. * Necessary to be able to change variable names. */ - addReference(_identifier: Identifier): void {} + addReference(_identifier: IdentifierBase): void {} private onlyFunctionCallUsed = true; /** @@ -103,10 +103,10 @@ export default class Variable extends ExpressionEntity { } /** - * Marks this variable as being part of the bundle, which is usually the case when one of - * its identifiers becomes part of the bundle. Returns true if it has not been included - * previously. - * Once a variable is included, it should take care all its declarations are included. + * Marks this variable as being part of the bundle, which is usually the case + * when one of its identifiers becomes part of the bundle. Returns true if it + * has not been included previously. Once a variable is included, it should + * take care all its declarations are included. */ include(): void { this.included = true; diff --git a/test/form/samples/jsx/preserves-jsx-child/_expected.js b/test/form/samples/jsx/preserves-jsx-child/_expected.js index 183372e19a6..3897e5354e2 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-child/_expected.js @@ -1,5 +1,4 @@ -import 'react'; - +const Foo = () => {}; const result = ; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-child/main.js b/test/form/samples/jsx/preserves-jsx-child/main.js index 6310739e2a4..c863c74f668 100644 --- a/test/form/samples/jsx/preserves-jsx-child/main.js +++ b/test/form/samples/jsx/preserves-jsx-child/main.js @@ -1,4 +1,2 @@ -import React from "react"; - const Foo = () => {}; export const result = ; diff --git a/test/form/samples/jsx/preserves-jsx-closing/_expected.js b/test/form/samples/jsx/preserves-jsx-closing/_expected.js index 90f20750cac..7b202a3cf51 100644 --- a/test/form/samples/jsx/preserves-jsx-closing/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-closing/_expected.js @@ -1,5 +1,4 @@ -import 'react'; - +const Foo = () => {}; const result = ; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-closing/main.js b/test/form/samples/jsx/preserves-jsx-closing/main.js index f462943915c..9c2716421ca 100644 --- a/test/form/samples/jsx/preserves-jsx-closing/main.js +++ b/test/form/samples/jsx/preserves-jsx-closing/main.js @@ -1,4 +1,2 @@ -import React from "react"; - const Foo = () => {}; export const result = ; diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js index 8c81c0b0c7a..406e2404763 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js @@ -1,5 +1,4 @@ -import 'react'; - +const Foo = () => {}; const result = {}; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/main.js b/test/form/samples/jsx/preserves-jsx-empty-expression/main.js index 90c47f081b4..cb5632fc2f2 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/main.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/main.js @@ -1,4 +1,2 @@ -import React from 'react'; - const Foo = () => {}; export const result = {}; diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js index 380d04d0873..07a102b2a7c 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js @@ -1,5 +1,4 @@ -import 'react'; - +const Foo = () => {}; const result = {'test'}; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js index 2122023f0d9..22471ece420 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js +++ b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js @@ -1,4 +1,2 @@ -import React from 'react'; - const Foo = () => {}; export const result = {'test'}; diff --git a/test/form/samples/jsx/preserves-jsx-fragment/_expected.js b/test/form/samples/jsx/preserves-jsx-fragment/_expected.js index 47bcf4b958f..594a20cbde1 100644 --- a/test/form/samples/jsx/preserves-jsx-fragment/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-fragment/_expected.js @@ -1,5 +1,4 @@ -import 'react'; - +const Foo = () => {}; const result = <>; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-fragment/main.js b/test/form/samples/jsx/preserves-jsx-fragment/main.js index 3b649ee8f9b..14a6baf4604 100644 --- a/test/form/samples/jsx/preserves-jsx-fragment/main.js +++ b/test/form/samples/jsx/preserves-jsx-fragment/main.js @@ -1,4 +1,2 @@ -import React from "react"; - const Foo = () => {}; export const result = <>; diff --git a/test/form/samples/jsx/preserves-jsx-text/_expected.js b/test/form/samples/jsx/preserves-jsx-text/_expected.js index d28dcc21e13..63fade57bb1 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-text/_expected.js @@ -1,5 +1,4 @@ -import 'react'; - +const Foo = () => {}; const result = some-text; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-text/main.js b/test/form/samples/jsx/preserves-jsx-text/main.js index bb7a2e87cf3..6af9245a78f 100644 --- a/test/form/samples/jsx/preserves-jsx-text/main.js +++ b/test/form/samples/jsx/preserves-jsx-text/main.js @@ -1,4 +1,2 @@ -import React from "react"; - const Foo = () => {}; export const result = some-text; diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js b/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js index 51b08f79ed5..90df741f466 100644 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js @@ -1,5 +1,4 @@ -import 'react'; - +const Foo = () => {}; const result = ; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/main.js b/test/form/samples/jsx/preserves-jsx-with-attributes/main.js index df93c1f9854..d5a0cfaab7b 100644 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/main.js +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/main.js @@ -1,4 +1,2 @@ -import React from "react"; - const Foo = () => {}; export const result = ; diff --git a/test/form/samples/jsx/preserves-jsx/_expected.js b/test/form/samples/jsx/preserves-jsx/_expected.js index fb207c9ffcb..bbb6ca29420 100644 --- a/test/form/samples/jsx/preserves-jsx/_expected.js +++ b/test/form/samples/jsx/preserves-jsx/_expected.js @@ -1,5 +1,6 @@ -import 'react'; +import React from "react"; +const Foo = () => {}; const result = ; export { result }; diff --git a/test/form/samples/jsx/transpiles-react/_expected.js b/test/form/samples/jsx/transpiles-react/_expected.js index 8250e6193c2..1d99eacf9a9 100644 --- a/test/form/samples/jsx/transpiles-react/_expected.js +++ b/test/form/samples/jsx/transpiles-react/_expected.js @@ -1,4 +1,6 @@ import React from "react"; const Foo = () => {}; -export const result = React.createElement(Foo, null); +const result = /*#__PURE__*/React.createElement(Foo, null); + +export { result }; From 56557187131092dbe9eb13b30a631c87ab0bb7c3 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Wed, 1 May 2024 06:15:28 +0200 Subject: [PATCH 14/62] Use correct JSX types --- rust/parse_ast/src/convert_ast/converter.rs | 7 ++++--- .../convert_ast/converter/ast_constants.rs | 8 ++++---- scripts/ast-types.js | 9 +++++---- src/ast/bufferParsers.ts | 8 ++++---- src/ast/childNodeKeys.ts | 4 ++-- src/ast/nodes/JSXAttribute.ts | 11 ++++++---- src/ast/nodes/JSXClosingElement.ts | 2 +- src/ast/nodes/JSXClosingFragment.ts | 2 +- src/ast/nodes/JSXElement.ts | 20 ++++++++++++++----- src/ast/nodes/JSXExpressionContainer.ts | 3 ++- src/ast/nodes/JSXFragment.ts | 20 ++++++++++++++----- src/ast/nodes/JSXOpeningElement.ts | 4 ++-- src/utils/bufferToAst.ts | 10 +++++----- 13 files changed, 67 insertions(+), 41 deletions(-) diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 0719053c240..86620358089 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -436,7 +436,7 @@ impl<'a> AstConverter<'a> { fn convert_jsx_attribute_name(&mut self, jsx_attribute_name: &JSXAttrName) { match jsx_attribute_name { JSXAttrName::Ident(identifier) => { - self.store_jsx_identifier(identifier); + self.store_jsx_identifier(&identifier.span, &identifier.sym); } JSXAttrName::JSXNamespacedName(_jsx_namespaced_name) => { unimplemented!("JSXElementName::JSXNamespacedName") @@ -488,7 +488,9 @@ impl<'a> AstConverter<'a> { fn convert_jsx_element_name(&mut self, jsx_element_name: &JSXElementName) { match jsx_element_name { - JSXElementName::Ident(identifier) => self.store_jsx_identifier(identifier), + JSXElementName::Ident(identifier) => { + self.store_jsx_identifier(&identifier.span, &identifier.sym) + } JSXElementName::JSXMemberExpr(_jsx_member_expression) => { unimplemented!("JSXElementName::JSXMemberExpr") } @@ -940,7 +942,6 @@ impl<'a> AstConverter<'a> { // end self.add_end(end_position, &jsx_text.span); } - } pub fn convert_annotation(buffer: &mut Vec, annotation: &ConvertedAnnotation) { diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index b82479e5552..03fb9dcd9c6 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -147,8 +147,8 @@ pub const JSX_CLOSING_FRAGMENT_RESERVED_BYTES: usize = 4; pub const JSX_ELEMENT_RESERVED_BYTES: usize = 16; pub const JSX_ELEMENT_OPENING_ELEMENT_OFFSET: usize = 4; -pub const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 8; -pub const JSX_ELEMENT_CHILDREN_OFFSET: usize = 12; +pub const JSX_ELEMENT_CHILDREN_OFFSET: usize = 8; +pub const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 12; pub const JSX_EMPTY_EXPRESSION_RESERVED_BYTES: usize = 4; @@ -157,8 +157,8 @@ pub const JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET: usize = 4; pub const JSX_FRAGMENT_RESERVED_BYTES: usize = 16; pub const JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET: usize = 4; -pub const JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET: usize = 8; -pub const JSX_FRAGMENT_CHILDREN_OFFSET: usize = 12; +pub const JSX_FRAGMENT_CHILDREN_OFFSET: usize = 8; +pub const JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET: usize = 12; pub const JSX_IDENTIFIER_RESERVED_BYTES: usize = 8; pub const JSX_IDENTIFIER_NAME_OFFSET: usize = 4; diff --git a/scripts/ast-types.js b/scripts/ast-types.js index ac2bf94b634..ed5ab4f976b 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -23,6 +23,7 @@ * For encoded non-JavaScript AST nodes like TypeScript or JSX, we try to follow * the format of typescript-eslint, which can be derived from their playground * https://typescript-eslint.io/play/#showAST=es&fileType=.tsx + * For JSX, see also https://github.com/facebook/jsx/blob/main/AST.md */ /** @typedef {"Node"|"OptionalNode"|"NodeList"|"Annotations"|"InvalidAnnotations"|"String"|"FixedString"|"OptionalString"|"Float"} FieldType */ @@ -410,8 +411,8 @@ export const AST_NODES = { estreeType: 'any', fields: [ ['openingElement', 'Node'], - ['closingElement', 'OptionalNode'], - ['children', 'NodeList'] + ['children', 'NodeList'], + ['closingElement', 'OptionalNode'] ], useMacro: false }, @@ -428,8 +429,8 @@ export const AST_NODES = { estreeType: 'any', fields: [ ['openingFragment', 'Node'], - ['closingFragment', 'Node'], - ['children', 'NodeList'] + ['children', 'NodeList'], + ['closingFragment', 'Node'] ], useMacro: false }, diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index 8551166662d..f411a62e8dc 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -610,12 +610,12 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ function jsxElement(node: JSXElement, position, buffer) { const { scope } = node; node.openingElement = convertNode(node, scope, buffer[position], buffer); - const closingElementPosition = buffer[position + 1]; + node.children = convertNodeList(node, scope, buffer[position + 1], buffer); + const closingElementPosition = buffer[position + 2]; node.closingElement = closingElementPosition === 0 ? null : convertNode(node, scope, closingElementPosition, buffer); - node.children = convertNodeList(node, scope, buffer[position + 2], buffer); }, function jsxEmptyExpression() {}, function jsxExpressionContainer(node: JSXExpressionContainer, position, buffer) { @@ -625,8 +625,8 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ function jsxFragment(node: JSXFragment, position, buffer) { const { scope } = node; node.openingFragment = convertNode(node, scope, buffer[position], buffer); - node.closingFragment = convertNode(node, scope, buffer[position + 1], buffer); - node.children = convertNodeList(node, scope, buffer[position + 2], buffer); + node.children = convertNodeList(node, scope, buffer[position + 1], buffer); + node.closingFragment = convertNode(node, scope, buffer[position + 2], buffer); }, function jsxIdentifier(node: JSXIdentifier, position, buffer) { node.name = buffer.convertString(buffer[position]); diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index 44f35c2238d..01ee687f231 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -44,10 +44,10 @@ export const childNodeKeys: Record = { JSXAttribute: ['name', 'value'], JSXClosingElement: ['name'], JSXClosingFragment: [], - JSXElement: ['openingElement', 'closingElement', 'children'], + JSXElement: ['openingElement', 'children', 'closingElement'], JSXEmptyExpression: [], JSXExpressionContainer: ['expression'], - JSXFragment: ['openingFragment', 'closingFragment', 'children'], + JSXFragment: ['openingFragment', 'children', 'closingFragment'], JSXIdentifier: [], JSXOpeningElement: ['name', 'attributes'], JSXOpeningFragment: [], diff --git a/src/ast/nodes/JSXAttribute.ts b/src/ast/nodes/JSXAttribute.ts index a7430aeef9f..89ae789ae43 100644 --- a/src/ast/nodes/JSXAttribute.ts +++ b/src/ast/nodes/JSXAttribute.ts @@ -1,10 +1,13 @@ +import type JSXElement from './JSXElement'; +import type JSXExpressionContainer from './JSXExpressionContainer'; +import type JSXFragment from './JSXFragment'; import type JSXIdentifier from './JSXIdentifier'; +import type Literal from './Literal'; import type * as NodeType from './NodeType'; -import type { ExpressionNode } from './shared/Node'; import { NodeBase } from './shared/Node'; export default class JSXAttribute extends NodeBase { - declare name: JSXIdentifier; - declare value: ExpressionNode | null; - declare type: NodeType.tJSXAttribute; + type!: NodeType.tJSXAttribute; + name!: JSXIdentifier /* TODO | JSXNamespacedName */; + value!: Literal | JSXExpressionContainer | JSXElement | JSXFragment | null; } diff --git a/src/ast/nodes/JSXClosingElement.ts b/src/ast/nodes/JSXClosingElement.ts index 97e8e896175..792f5c31b07 100644 --- a/src/ast/nodes/JSXClosingElement.ts +++ b/src/ast/nodes/JSXClosingElement.ts @@ -4,5 +4,5 @@ import { NodeBase } from './shared/Node'; export default class JSXClosingElement extends NodeBase { type!: NodeType.tJSXClosingElement; - name!: JSXIdentifier; + name!: JSXIdentifier /* TODO | JSXMemberExpression | JSXNamespacedName */; } diff --git a/src/ast/nodes/JSXClosingFragment.ts b/src/ast/nodes/JSXClosingFragment.ts index 5a3b0c2e253..8b7e3699618 100644 --- a/src/ast/nodes/JSXClosingFragment.ts +++ b/src/ast/nodes/JSXClosingFragment.ts @@ -2,5 +2,5 @@ import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; export default class JSXClosingFragment extends NodeBase { - declare type: NodeType.tJSXElement; + type!: NodeType.tJSXClosingFragment; } diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 0cbe9b76c32..a91eafa3ae9 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -1,9 +1,19 @@ +import type JSXClosingElement from './JSXClosingElement'; +import type JSXExpressionContainer from './JSXExpressionContainer'; +import type JSXFragment from './JSXFragment'; +import type JSXOpeningElement from './JSXOpeningElement'; +import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; -import { type ExpressionNode, NodeBase } from './shared/Node'; +import { NodeBase } from './shared/Node'; export default class JSXElement extends NodeBase { - declare closingElement: unknown; - declare openingElement: unknown; - declare type: NodeType.tJSXElement; - declare children: ExpressionNode[]; + type!: NodeType.tJSXElement; + openingElement!: JSXOpeningElement; + closingElement!: JSXClosingElement | null; + children!: ( + | JSXText + | JSXExpressionContainer + | JSXElement + | JSXFragment + ) /* TODO | JSXSpreadChild */[]; } diff --git a/src/ast/nodes/JSXExpressionContainer.ts b/src/ast/nodes/JSXExpressionContainer.ts index 09f68b47d77..703aa682214 100644 --- a/src/ast/nodes/JSXExpressionContainer.ts +++ b/src/ast/nodes/JSXExpressionContainer.ts @@ -1,8 +1,9 @@ +import type JSXEmptyExpression from './JSXEmptyExpression'; import type * as NodeType from './NodeType'; import type { ExpressionNode } from './shared/Node'; import { NodeBase } from './shared/Node'; export default class JSXExpressionContainer extends NodeBase { type!: NodeType.tJSXExpressionContainer; - expression!: ExpressionNode; + expression!: ExpressionNode | JSXEmptyExpression; } diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index dc8a8ba8abf..f7531529b6a 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -1,10 +1,20 @@ +import type JSXClosingFragment from './JSXClosingFragment'; +import type JSXElement from './JSXElement'; +import type JSXExpressionContainer from './JSXExpressionContainer'; +import type JSXFragment from './JSXFragment'; import type JSXOpeningFragment from './JSXOpeningFragment'; +import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; -import { type ExpressionNode, NodeBase } from './shared/Node'; +import { NodeBase } from './shared/Node'; export default class JsxElement extends NodeBase { - declare closingFragment: unknown; - declare openingFragment: JSXOpeningFragment; - declare type: NodeType.tJSXElement; - declare children: ExpressionNode[]; + type!: NodeType.tJSXElement; + openingFragment!: JSXOpeningFragment; + children!: ( + | JSXText + | JSXExpressionContainer /* TODO | JSXSpreadChild */ + | JSXElement + | JSXFragment + )[]; + closingFragment!: JSXClosingFragment; } diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index f771de4252b..edae9317279 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -5,7 +5,7 @@ import { NodeBase } from './shared/Node'; export default class JSXOpeningElement extends NodeBase { type!: NodeType.tJSXOpeningElement; - selfClosing!: boolean; name!: JSXIdentifier; - attributes!: JSXAttribute[]; + attributes!: JSXAttribute /* TODO | JSXSpreadAttribute */[]; + selfClosing!: boolean; } diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index c8f73f6e597..0a8ec0241f0 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -476,15 +476,15 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ }; }, function jsxElement(position, buffer): JSXElementNode { - const closingElementPosition = buffer[position + 3]; + const closingElementPosition = buffer[position + 4]; return { type: 'JSXElement', start: buffer[position], end: buffer[position + 1], openingElement: convertNode(buffer[position + 2], buffer), + children: convertNodeList(buffer[position + 3], buffer), closingElement: - closingElementPosition === 0 ? null : convertNode(closingElementPosition, buffer), - children: convertNodeList(buffer[position + 4], buffer) + closingElementPosition === 0 ? null : convertNode(closingElementPosition, buffer) }; }, function jsxEmptyExpression(position, buffer): JSXEmptyExpressionNode { @@ -508,8 +508,8 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ start: buffer[position], end: buffer[position + 1], openingFragment: convertNode(buffer[position + 2], buffer), - closingFragment: convertNode(buffer[position + 3], buffer), - children: convertNodeList(buffer[position + 4], buffer) + children: convertNodeList(buffer[position + 3], buffer), + closingFragment: convertNode(buffer[position + 4], buffer) }; }, function jsxIdentifier(position, buffer): JSXIdentifierNode { From fcb49b28cfe9d385d071534e380b3be0d8eb2e12 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Wed, 1 May 2024 07:03:43 +0200 Subject: [PATCH 15/62] Ensure React is included when JSX is used --- src/ast/nodes/JSXElement.ts | 41 +++++++++++++++++++ src/ast/scopes/ChildScope.ts | 6 +++ src/ast/scopes/GlobalScope.ts | 4 ++ src/ast/scopes/Scope.ts | 9 ++++ src/ast/variables/Variable.ts | 4 ++ .../jsx/keep-react-when-preserving/_config.js | 8 ++++ .../keep-react-when-preserving/_expected.js | 6 +++ .../jsx/keep-react-when-preserving/dep1.js | 4 ++ .../jsx/keep-react-when-preserving/dep2.js | 4 ++ .../jsx/keep-react-when-preserving/main.js | 4 ++ .../samples/jsx/preserves-jsx/_expected.js | 2 +- 11 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 test/form/samples/jsx/keep-react-when-preserving/_config.js create mode 100644 test/form/samples/jsx/keep-react-when-preserving/_expected.js create mode 100644 test/form/samples/jsx/keep-react-when-preserving/dep1.js create mode 100644 test/form/samples/jsx/keep-react-when-preserving/dep2.js create mode 100644 test/form/samples/jsx/keep-react-when-preserving/main.js diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index a91eafa3ae9..741acc2b2d9 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -1,9 +1,14 @@ +import type { InclusionContext } from '../ExecutionContext'; +import LocalVariable from '../variables/LocalVariable'; +import type Variable from '../variables/Variable'; import type JSXClosingElement from './JSXClosingElement'; import type JSXExpressionContainer from './JSXExpressionContainer'; import type JSXFragment from './JSXFragment'; import type JSXOpeningElement from './JSXOpeningElement'; import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; +import type { InclusionOptions } from './shared/Expression'; +import type { IncludeChildren } from './shared/Node'; import { NodeBase } from './shared/Node'; export default class JSXElement extends NodeBase { @@ -16,4 +21,40 @@ export default class JSXElement extends NodeBase { | JSXElement | JSXFragment ) /* TODO | JSXSpreadChild */[]; + private factoryVariable: Variable | null = null; + + bind() { + super.bind(); + if (this.scope.context.options.jsx === 'preserve') { + // And also make sure it is always called "react" + this.factoryVariable = this.scope.findVariable('React'); + } + } + + include( + context: InclusionContext, + includeChildrenRecursively: IncludeChildren, + options?: InclusionOptions + ): void { + if (!this.deoptimized) this.applyDeoptimizations(); + if (!this.included && this.factoryVariable !== null) { + // TODO can we rework this so that we throw when different JSX elements would use different React variables? + // This should probably rely on using a different way of specifying "preserve" mode with factory variables + // This pretends we are accessing a global variable of the same name + this.scope.findGlobal('React'); + // This excludes this variable from renaming + this.factoryVariable.globalName = 'React'; + this.scope.context.includeVariableInModule(this.factoryVariable); + } + super.include(context, includeChildrenRecursively, options); + } + + protected applyDeoptimizations(): void { + this.deoptimized = true; + if (this.factoryVariable instanceof LocalVariable) { + this.factoryVariable.consolidateInitializers(); + this.factoryVariable.addUsedPlace(this); + this.scope.context.requestTreeshakingPass(); + } + } } diff --git a/src/ast/scopes/ChildScope.ts b/src/ast/scopes/ChildScope.ts index d13f83af4e2..50d6afa271d 100644 --- a/src/ast/scopes/ChildScope.ts +++ b/src/ast/scopes/ChildScope.ts @@ -106,6 +106,12 @@ export default class ChildScope extends Scope { return (this.parent as ChildScope).findLexicalBoundary(); } + findGlobal(name: string): Variable { + const variable = this.parent.findVariable(name); + this.accessedOutsideVariables.set(name, variable); + return variable; + } + findVariable(name: string): Variable { const knownVariable = this.variables.get(name) || this.accessedOutsideVariables.get(name); if (knownVariable) { diff --git a/src/ast/scopes/GlobalScope.ts b/src/ast/scopes/GlobalScope.ts index 08c94f0f879..b31ef03ba2b 100644 --- a/src/ast/scopes/GlobalScope.ts +++ b/src/ast/scopes/GlobalScope.ts @@ -11,6 +11,10 @@ export default class GlobalScope extends Scope { this.variables.set('undefined', new UndefinedVariable()); } + findGlobal(name: string): Variable { + return this.findVariable(name); + } + findVariable(name: string): Variable { let variable = this.variables.get(name); if (!variable) { diff --git a/src/ast/scopes/Scope.ts b/src/ast/scopes/Scope.ts index eaeea352d7d..9d0146de2f8 100644 --- a/src/ast/scopes/Scope.ts +++ b/src/ast/scopes/Scope.ts @@ -54,6 +54,15 @@ export default class Scope { return this.variables.has(name); } + /** + * This allows us to protect the name of a variable by pretending we also + * include a global variable of the same name. + */ + findGlobal(_name: string): void { + /* istanbul ignore next */ + throw new Error('Internal Error: findGlobal needs to be implemented by a subclass'); + } + findVariable(_name: string): Variable { /* istanbul ignore next */ throw new Error('Internal Error: findVariable needs to be implemented by a subclass'); diff --git a/src/ast/variables/Variable.ts b/src/ast/variables/Variable.ts index f77ce67fd04..2b8a1924f47 100644 --- a/src/ast/variables/Variable.ts +++ b/src/ast/variables/Variable.ts @@ -15,6 +15,7 @@ import type { ObjectPath } from '../utils/PathTracker'; export default class Variable extends ExpressionEntity { alwaysRendered = false; forbiddenNames: Set | null = null; + globalName: string | null = null; initReached = false; isId = false; // both NamespaceVariable and ExternalVariable can be namespaces @@ -84,6 +85,9 @@ export default class Variable extends ExpressionEntity { getPropertyAccess: (name: string) => string, useOriginalName?: RenderOptions['useOriginalName'] ): string { + if (this.globalName) { + return this.globalName; + } if (useOriginalName?.(this)) { return this.name; } diff --git a/test/form/samples/jsx/keep-react-when-preserving/_config.js b/test/form/samples/jsx/keep-react-when-preserving/_config.js new file mode 100644 index 00000000000..fde4f2fd2a7 --- /dev/null +++ b/test/form/samples/jsx/keep-react-when-preserving/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + // TODO This should actually be a funtion test that throws + solo: true, + description: 'this ensures the local React variable is not renamed when preserving JSX output', + options: { + jsx: 'preserve' + } +}); diff --git a/test/form/samples/jsx/keep-react-when-preserving/_expected.js b/test/form/samples/jsx/keep-react-when-preserving/_expected.js new file mode 100644 index 00000000000..2f1d81a4a65 --- /dev/null +++ b/test/form/samples/jsx/keep-react-when-preserving/_expected.js @@ -0,0 +1,6 @@ +import React from 'react'; + +const Foo = () => {}; +const result = ; + +export { result }; diff --git a/test/form/samples/jsx/keep-react-when-preserving/dep1.js b/test/form/samples/jsx/keep-react-when-preserving/dep1.js new file mode 100644 index 00000000000..3dd027858b4 --- /dev/null +++ b/test/form/samples/jsx/keep-react-when-preserving/dep1.js @@ -0,0 +1,4 @@ +const React = 'React1'; + +const Foo = () => {}; +export const foo1 = ; diff --git a/test/form/samples/jsx/keep-react-when-preserving/dep2.js b/test/form/samples/jsx/keep-react-when-preserving/dep2.js new file mode 100644 index 00000000000..2c12b32afd1 --- /dev/null +++ b/test/form/samples/jsx/keep-react-when-preserving/dep2.js @@ -0,0 +1,4 @@ +const React = 'React2'; + +const Foo = () => {}; +export const foo2 = ; diff --git a/test/form/samples/jsx/keep-react-when-preserving/main.js b/test/form/samples/jsx/keep-react-when-preserving/main.js new file mode 100644 index 00000000000..77f3bfd706f --- /dev/null +++ b/test/form/samples/jsx/keep-react-when-preserving/main.js @@ -0,0 +1,4 @@ +import { foo1 } from "./dep1"; +import { foo2 } from "./dep2"; + +console.log(foo1, foo2); diff --git a/test/form/samples/jsx/preserves-jsx/_expected.js b/test/form/samples/jsx/preserves-jsx/_expected.js index bbb6ca29420..2f1d81a4a65 100644 --- a/test/form/samples/jsx/preserves-jsx/_expected.js +++ b/test/form/samples/jsx/preserves-jsx/_expected.js @@ -1,4 +1,4 @@ -import React from "react"; +import React from 'react'; const Foo = () => {}; const result = ; From 63430c9a3f52464358c95214f9c68c269a9449e3 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Wed, 8 May 2024 06:52:33 +0200 Subject: [PATCH 16/62] Rework JSX option and global variable handling for preserving --- src/ast/nodes/JSXElement.ts | 41 +++++++++++-------- src/rollup/types.d.ts | 20 ++++++--- src/utils/options/normalizeInputOptions.ts | 17 +++++--- src/utils/options/options.ts | 14 ++++++- .../_config.js | 2 +- .../_expected.js | 0 .../dep1.js | 0 .../dep2.js | 0 .../main.js | 0 .../form/samples/jsx/preserves-jsx/_config.js | 4 +- .../samples/jsx/preserves-jsx/_expected.js | 2 - test/form/samples/jsx/preserves-jsx/main.js | 2 - .../jsx/preserves-react-local/_config.js | 9 ++++ .../jsx/preserves-react-local/_expected.js | 13 ++++++ .../samples/jsx/preserves-react-local/jsx.js | 5 +++ .../samples/jsx/preserves-react-local/main.js | 3 ++ .../jsx/preserves-react-local/other1.js | 3 ++ .../jsx/preserves-react-local/other2.js | 3 ++ .../samples/jsx/preserves-react/_config.js | 9 ++++ .../samples/jsx/preserves-react/_expected.js | 12 ++++++ test/form/samples/jsx/preserves-react/jsx.js | 4 ++ test/form/samples/jsx/preserves-react/main.js | 3 ++ .../samples/jsx/preserves-react/other1.js | 3 ++ .../samples/jsx/preserves-react/other2.js | 3 ++ 24 files changed, 134 insertions(+), 38 deletions(-) rename test/form/samples/jsx/{keep-react-when-preserving => jsx-preserve-react-conflict}/_config.js (74%) rename test/form/samples/jsx/{keep-react-when-preserving => jsx-preserve-react-conflict}/_expected.js (100%) rename test/form/samples/jsx/{keep-react-when-preserving => jsx-preserve-react-conflict}/dep1.js (100%) rename test/form/samples/jsx/{keep-react-when-preserving => jsx-preserve-react-conflict}/dep2.js (100%) rename test/form/samples/jsx/{keep-react-when-preserving => jsx-preserve-react-conflict}/main.js (100%) create mode 100644 test/form/samples/jsx/preserves-react-local/_config.js create mode 100644 test/form/samples/jsx/preserves-react-local/_expected.js create mode 100644 test/form/samples/jsx/preserves-react-local/jsx.js create mode 100644 test/form/samples/jsx/preserves-react-local/main.js create mode 100644 test/form/samples/jsx/preserves-react-local/other1.js create mode 100644 test/form/samples/jsx/preserves-react-local/other2.js create mode 100644 test/form/samples/jsx/preserves-react/_config.js create mode 100644 test/form/samples/jsx/preserves-react/_expected.js create mode 100644 test/form/samples/jsx/preserves-react/jsx.js create mode 100644 test/form/samples/jsx/preserves-react/main.js create mode 100644 test/form/samples/jsx/preserves-react/other1.js create mode 100644 test/form/samples/jsx/preserves-react/other2.js diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 741acc2b2d9..3308fef0cde 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -21,13 +21,15 @@ export default class JSXElement extends NodeBase { | JSXElement | JSXFragment ) /* TODO | JSXSpreadChild */[]; - private factoryVariable: Variable | null = null; + private factoryVariables = new Map(); bind() { super.bind(); - if (this.scope.context.options.jsx === 'preserve') { - // And also make sure it is always called "react" - this.factoryVariable = this.scope.findVariable('React'); + const { jsx } = this.scope.context.options; + if (jsx && jsx.preserve) { + for (const name of jsx.factoryGlobals) { + this.factoryVariables.set(name, this.scope.findVariable(name)); + } } } @@ -37,24 +39,31 @@ export default class JSXElement extends NodeBase { options?: InclusionOptions ): void { if (!this.deoptimized) this.applyDeoptimizations(); - if (!this.included && this.factoryVariable !== null) { - // TODO can we rework this so that we throw when different JSX elements would use different React variables? - // This should probably rely on using a different way of specifying "preserve" mode with factory variables - // This pretends we are accessing a global variable of the same name - this.scope.findGlobal('React'); - // This excludes this variable from renaming - this.factoryVariable.globalName = 'React'; - this.scope.context.includeVariableInModule(this.factoryVariable); + if (!this.included) { + const { jsx } = this.scope.context.options; + if (jsx && jsx.preserve) { + // TODO can we rework this so that we throw when different JSX elements would use different React variables? + for (const [name, factoryVariable] of this.factoryVariables) { + // This pretends we are accessing an included global variable of the same name + const globalVariable = this.scope.findGlobal(name); + globalVariable.include(); + // This excludes this variable from renaming + factoryVariable.globalName = name; + this.scope.context.includeVariableInModule(factoryVariable); + } + } } super.include(context, includeChildrenRecursively, options); } protected applyDeoptimizations(): void { this.deoptimized = true; - if (this.factoryVariable instanceof LocalVariable) { - this.factoryVariable.consolidateInitializers(); - this.factoryVariable.addUsedPlace(this); - this.scope.context.requestTreeshakingPass(); + for (const factoryVariable of this.factoryVariables.values()) { + if (factoryVariable instanceof LocalVariable) { + factoryVariable.consolidateInitializers(); + factoryVariable.addUsedPlace(this); + this.scope.context.requestTreeshakingPass(); + } } } } diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 4aff69892a0..baf0b253c2a 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -523,18 +523,26 @@ export interface Plugin extends OutputPlugin, Partial { api?: A; } -export type JsxPreset = 'react' | 'react-jsx'; +export type JsxPreset = 'react' | 'react-jsx' | 'preserve' | 'preserve-react'; -export interface NormalizedJsxOptions { +export type NormalizedJsxOptions = NormalizedJsxPreserveOptions | NormalizedJsxTranspileOptions; + +interface NormalizedJsxTranspileOptions { factory: string; fragmentFactory: string; importSource: string | null; + preserve: false; } -export interface JsxOptions extends Partial { - preset?: JsxPreset; +interface NormalizedJsxPreserveOptions { + factoryGlobals: string[]; + preserve: true; } +export type JsxOptions = Partial & { + preset?: JsxPreset; +}; + export type TreeshakingPreset = 'smallest' | 'safest' | 'recommended'; export interface NormalizedTreeshakingOptions { @@ -605,7 +613,7 @@ export interface InputOptions { experimentalLogSideEffects?: boolean; external?: ExternalOption; input?: InputOption; - jsx?: false | 'preserve' | JsxOptions; + jsx?: false | JsxOptions; logLevel?: LogLevelOption; makeAbsoluteExternalsRelative?: boolean | 'ifRelativeSource'; maxParallelFileOps?: number; @@ -633,7 +641,7 @@ export interface NormalizedInputOptions { experimentalLogSideEffects: boolean; external: IsExternal; input: string[] | Record; - jsx: false | 'preserve' | NormalizedJsxOptions; + jsx: false | NormalizedJsxOptions; logLevel: LogLevelOption; makeAbsoluteExternalsRelative: boolean | 'ifRelativeSource'; maxParallelFileOps: number; diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index 5adf02b1ecf..41f21afd643 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -119,7 +119,6 @@ const getInput = (config: InputOptions): NormalizedInputOptions['input'] => { const getJsx = (config: InputOptions): NormalizedInputOptions['jsx'] => { const configJsx = config.jsx; if (!configJsx) return false; - if (configJsx === 'preserve') return 'preserve'; const configWithPreset = getOptionWithPreset( configJsx, jsxPresets, @@ -127,11 +126,17 @@ const getJsx = (config: InputOptions): NormalizedInputOptions['jsx'] => { URL_JSX, 'false, "preserve", ' ); - return { - factory: configWithPreset.factory || 'React.createElement', - fragmentFactory: configWithPreset.fragmentFactory || 'React.Fragment', - importSource: configWithPreset.importSource || null - }; + return configWithPreset.preserve + ? { + factoryGlobals: configWithPreset.factoryGlobals || EMPTY_ARRAY, + preserve: true + } + : { + factory: configWithPreset.factory || 'React.createElement', + fragmentFactory: configWithPreset.fragmentFactory || 'React.Fragment', + importSource: configWithPreset.importSource || null, + preserve: false + }; }; const getMaxParallelFileOps = ( diff --git a/src/utils/options/options.ts b/src/utils/options/options.ts index 995c2a67949..46897a424ef 100644 --- a/src/utils/options/options.ts +++ b/src/utils/options/options.ts @@ -140,15 +140,25 @@ export const treeshakePresets: { export const jsxPresets: { [key in NonNullable['preset']>]: NormalizedJsxOptions; } = { + preserve: { + factoryGlobals: EMPTY_ARRAY as never[], + preserve: true + }, + 'preserve-react': { + factoryGlobals: ['React'], + preserve: true + }, react: { factory: 'React.createElement', fragmentFactory: 'React.Fragment', - importSource: null + importSource: null, + preserve: false }, 'react-jsx': { factory: 'jsx', fragmentFactory: 'Fragment', - importSource: 'react' + importSource: 'react', + preserve: false } }; diff --git a/test/form/samples/jsx/keep-react-when-preserving/_config.js b/test/form/samples/jsx/jsx-preserve-react-conflict/_config.js similarity index 74% rename from test/form/samples/jsx/keep-react-when-preserving/_config.js rename to test/form/samples/jsx/jsx-preserve-react-conflict/_config.js index fde4f2fd2a7..3130327d73e 100644 --- a/test/form/samples/jsx/keep-react-when-preserving/_config.js +++ b/test/form/samples/jsx/jsx-preserve-react-conflict/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // TODO This should actually be a funtion test that throws + // TODO This should actually be a function test that throws solo: true, description: 'this ensures the local React variable is not renamed when preserving JSX output', options: { diff --git a/test/form/samples/jsx/keep-react-when-preserving/_expected.js b/test/form/samples/jsx/jsx-preserve-react-conflict/_expected.js similarity index 100% rename from test/form/samples/jsx/keep-react-when-preserving/_expected.js rename to test/form/samples/jsx/jsx-preserve-react-conflict/_expected.js diff --git a/test/form/samples/jsx/keep-react-when-preserving/dep1.js b/test/form/samples/jsx/jsx-preserve-react-conflict/dep1.js similarity index 100% rename from test/form/samples/jsx/keep-react-when-preserving/dep1.js rename to test/form/samples/jsx/jsx-preserve-react-conflict/dep1.js diff --git a/test/form/samples/jsx/keep-react-when-preserving/dep2.js b/test/form/samples/jsx/jsx-preserve-react-conflict/dep2.js similarity index 100% rename from test/form/samples/jsx/keep-react-when-preserving/dep2.js rename to test/form/samples/jsx/jsx-preserve-react-conflict/dep2.js diff --git a/test/form/samples/jsx/keep-react-when-preserving/main.js b/test/form/samples/jsx/jsx-preserve-react-conflict/main.js similarity index 100% rename from test/form/samples/jsx/keep-react-when-preserving/main.js rename to test/form/samples/jsx/jsx-preserve-react-conflict/main.js diff --git a/test/form/samples/jsx/preserves-jsx/_config.js b/test/form/samples/jsx/preserves-jsx/_config.js index 78de66a33bd..fd757675c75 100644 --- a/test/form/samples/jsx/preserves-jsx/_config.js +++ b/test/form/samples/jsx/preserves-jsx/_config.js @@ -2,8 +2,6 @@ module.exports = defineTest({ solo: true, description: 'preserves JSX output', options: { - external: ['react'], jsx: 'preserve' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] + } }); diff --git a/test/form/samples/jsx/preserves-jsx/_expected.js b/test/form/samples/jsx/preserves-jsx/_expected.js index 2f1d81a4a65..5764a03cb8e 100644 --- a/test/form/samples/jsx/preserves-jsx/_expected.js +++ b/test/form/samples/jsx/preserves-jsx/_expected.js @@ -1,5 +1,3 @@ -import React from 'react'; - const Foo = () => {}; const result = ; diff --git a/test/form/samples/jsx/preserves-jsx/main.js b/test/form/samples/jsx/preserves-jsx/main.js index 6dc07da2a1d..1e56ff70298 100644 --- a/test/form/samples/jsx/preserves-jsx/main.js +++ b/test/form/samples/jsx/preserves-jsx/main.js @@ -1,4 +1,2 @@ -import React from "react"; - const Foo = () => {}; export const result = ; diff --git a/test/form/samples/jsx/preserves-react-local/_config.js b/test/form/samples/jsx/preserves-react-local/_config.js new file mode 100644 index 00000000000..8e99dce7a67 --- /dev/null +++ b/test/form/samples/jsx/preserves-react-local/_config.js @@ -0,0 +1,9 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves local React variable when preserving JSX output', + options: { + external: ['react'], + jsx: 'preserve-react' + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] +}); diff --git a/test/form/samples/jsx/preserves-react-local/_expected.js b/test/form/samples/jsx/preserves-react-local/_expected.js new file mode 100644 index 00000000000..9ec83e05875 --- /dev/null +++ b/test/form/samples/jsx/preserves-react-local/_expected.js @@ -0,0 +1,13 @@ +import theReact from 'react'; + +const Foo$2 = () => {}; +const React$3 = () => {}; +console.log(Foo$2, React$3); + +const React = theReact; +const Foo$1 = () => {}; +console.log(); + +const Foo = () => {}; +const React$1 = () => {}; +console.log(Foo, React$1); diff --git a/test/form/samples/jsx/preserves-react-local/jsx.js b/test/form/samples/jsx/preserves-react-local/jsx.js new file mode 100644 index 00000000000..44e19d36489 --- /dev/null +++ b/test/form/samples/jsx/preserves-react-local/jsx.js @@ -0,0 +1,5 @@ +import theReact from "react"; + +const React = theReact; +const Foo = () => {}; +console.log(); diff --git a/test/form/samples/jsx/preserves-react-local/main.js b/test/form/samples/jsx/preserves-react-local/main.js new file mode 100644 index 00000000000..dfccae85926 --- /dev/null +++ b/test/form/samples/jsx/preserves-react-local/main.js @@ -0,0 +1,3 @@ +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/preserves-react-local/other1.js b/test/form/samples/jsx/preserves-react-local/other1.js new file mode 100644 index 00000000000..dc7480c221c --- /dev/null +++ b/test/form/samples/jsx/preserves-react-local/other1.js @@ -0,0 +1,3 @@ +const Foo = () => {}; +const React = () => {}; +console.log(Foo, React); diff --git a/test/form/samples/jsx/preserves-react-local/other2.js b/test/form/samples/jsx/preserves-react-local/other2.js new file mode 100644 index 00000000000..dc7480c221c --- /dev/null +++ b/test/form/samples/jsx/preserves-react-local/other2.js @@ -0,0 +1,3 @@ +const Foo = () => {}; +const React = () => {}; +console.log(Foo, React); diff --git a/test/form/samples/jsx/preserves-react/_config.js b/test/form/samples/jsx/preserves-react/_config.js new file mode 100644 index 00000000000..5ce9b42fbd9 --- /dev/null +++ b/test/form/samples/jsx/preserves-react/_config.js @@ -0,0 +1,9 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves React variable when preserving JSX output', + options: { + external: ['react'], + jsx: 'preserve-react' + }, + expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] +}); diff --git a/test/form/samples/jsx/preserves-react/_expected.js b/test/form/samples/jsx/preserves-react/_expected.js new file mode 100644 index 00000000000..62586a3c8a3 --- /dev/null +++ b/test/form/samples/jsx/preserves-react/_expected.js @@ -0,0 +1,12 @@ +import React from 'react'; + +const Foo$2 = () => {}; +const React$2 = () => {}; +console.log(Foo$2, React$2); + +const Foo$1 = () => {}; +console.log(); + +const Foo = () => {}; +const React$1 = () => {}; +console.log(Foo, React$1); diff --git a/test/form/samples/jsx/preserves-react/jsx.js b/test/form/samples/jsx/preserves-react/jsx.js new file mode 100644 index 00000000000..bb22f6edde5 --- /dev/null +++ b/test/form/samples/jsx/preserves-react/jsx.js @@ -0,0 +1,4 @@ +import React from "react"; + +const Foo = () => {}; +console.log(); diff --git a/test/form/samples/jsx/preserves-react/main.js b/test/form/samples/jsx/preserves-react/main.js new file mode 100644 index 00000000000..dfccae85926 --- /dev/null +++ b/test/form/samples/jsx/preserves-react/main.js @@ -0,0 +1,3 @@ +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/preserves-react/other1.js b/test/form/samples/jsx/preserves-react/other1.js new file mode 100644 index 00000000000..dc7480c221c --- /dev/null +++ b/test/form/samples/jsx/preserves-react/other1.js @@ -0,0 +1,3 @@ +const Foo = () => {}; +const React = () => {}; +console.log(Foo, React); diff --git a/test/form/samples/jsx/preserves-react/other2.js b/test/form/samples/jsx/preserves-react/other2.js new file mode 100644 index 00000000000..dc7480c221c --- /dev/null +++ b/test/form/samples/jsx/preserves-react/other2.js @@ -0,0 +1,3 @@ +const Foo = () => {}; +const React = () => {}; +console.log(Foo, React); From e7b75cddf97a340ad4b26af0f03a043cedb10a91 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Thu, 9 May 2024 10:13:13 +0200 Subject: [PATCH 17/62] Start work on transpilation support --- src/Module.ts | 25 +++++++++++ src/ast/nodes/JSXElement.ts | 44 +++++++++++++++++-- src/utils/parseImportAttributes.ts | 4 +- .../_config.js | 2 +- .../jsx/transpiles-react-jsx/_expected.js | 6 +++ .../main.js | 4 +- .../samples/jsx/transpiles-react/_expected.js | 6 --- 7 files changed, 77 insertions(+), 14 deletions(-) rename test/form/samples/jsx/{transpiles-react => transpiles-react-jsx}/_config.js (86%) create mode 100644 test/form/samples/jsx/transpiles-react-jsx/_expected.js rename test/form/samples/jsx/{transpiles-react => transpiles-react-jsx}/main.js (56%) delete mode 100644 test/form/samples/jsx/transpiles-react/_expected.js diff --git a/src/Module.ts b/src/Module.ts index 302788601a4..326154a9607 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -40,6 +40,8 @@ import type { ModuleJSON, ModuleOptions, NormalizedInputOptions, + NormalizedJsxOptions, + NormalizedJsxTranspileOptions, PartialNull, PreserveEntrySignaturesOption, ResolvedId, @@ -113,11 +115,13 @@ export interface AstContext { ) => void; addImport: (node: ImportDeclaration) => void; addImportMeta: (node: MetaProperty) => void; + addJsx: () => void; code: string; deoptimizationTracker: PathTracker; error: (properties: RollupLog, pos: number) => never; fileName: string; getExports: () => string[]; + getImportedJsxFactoryVariable: (baseName: string, pos: number) => Variable; getModuleExecIndex: () => number; getModuleName: () => string; getNodeConstructor: (name: string) => typeof NodeBase; @@ -869,11 +873,13 @@ export default class Module { addExport: this.addExport.bind(this), addImport: this.addImport.bind(this), addImportMeta: this.addImportMeta.bind(this), + addJsx: this.addJsx.bind(this), code, // Only needed for debugging deoptimizationTracker: this.graph.deoptimizationTracker, error: this.error.bind(this), fileName, // Needed for warnings getExports: this.getExports.bind(this), + getImportedJsxFactoryVariable: this.getImportedJsxFactoryVariable.bind(this), getModuleExecIndex: () => this.execIndex, getModuleName: this.basename.bind(this), getNodeConstructor: (name: string) => nodeConstructors[name] || nodeConstructors.UnknownNode, @@ -1147,6 +1153,13 @@ export default class Module { } } + private addJsx(): void { + const jsx = this.options.jsx as NormalizedJsxOptions; + if (!jsx.preserve && jsx.importSource && !this.sourcesWithAttributes.has(jsx.importSource)) { + this.sourcesWithAttributes.set(jsx.importSource, EMPTY_OBJECT); + } + } + private addImportMeta(node: MetaProperty): void { this.importMetas.push(node); } @@ -1233,6 +1246,18 @@ export default class Module { } } + private getImportedJsxFactoryVariable(baseName: string, nodeStart: number): Variable { + const { importSource } = this.scope.context.options.jsx as NormalizedJsxTranspileOptions; + const { id } = this.resolvedIds[importSource!]; + const module = this.graph.modulesById.get(id)!; + const [variable] = module.getVariableForExportName(baseName); + if (!variable) { + // TODO proper error + throw new Error('TODO ' + nodeStart); + } + return variable; + } + private getVariableFromNamespaceReexports( name: string, importerForSideEffects?: Module, diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 3308fef0cde..5094fa0a969 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -1,3 +1,6 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; +import type { RenderOptions } from '../../utils/renderHelpers'; import type { InclusionContext } from '../ExecutionContext'; import LocalVariable from '../variables/LocalVariable'; import type Variable from '../variables/Variable'; @@ -25,11 +28,20 @@ export default class JSXElement extends NodeBase { bind() { super.bind(); - const { jsx } = this.scope.context.options; - if (jsx && jsx.preserve) { + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + if (jsx.preserve) { for (const name of jsx.factoryGlobals) { this.factoryVariables.set(name, this.scope.findVariable(name)); } + } else if (jsx.importSource) { + const factoryBaseName = jsx.factory.split('.')[0]; + this.factoryVariables.set( + factoryBaseName, + this.scope.context.getImportedJsxFactoryVariable(factoryBaseName, this.start) + ); + } else { + // TODO handle non-imported + throw new Error('TODO'); } } @@ -40,8 +52,8 @@ export default class JSXElement extends NodeBase { ): void { if (!this.deoptimized) this.applyDeoptimizations(); if (!this.included) { - const { jsx } = this.scope.context.options; - if (jsx && jsx.preserve) { + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + if (jsx.preserve) { // TODO can we rework this so that we throw when different JSX elements would use different React variables? for (const [name, factoryVariable] of this.factoryVariables) { // This pretends we are accessing an included global variable of the same name @@ -51,11 +63,23 @@ export default class JSXElement extends NodeBase { factoryVariable.globalName = name; this.scope.context.includeVariableInModule(factoryVariable); } + } else if (jsx.importSource) { + for (const factoryVariable of this.factoryVariables.values()) { + this.scope.context.includeVariableInModule(factoryVariable); + } + } else { + // TODO handle non-imported + throw new Error('TODO'); } } super.include(context, includeChildrenRecursively, options); } + initialise(): void { + super.initialise(); + this.scope.context.addJsx(); + } + protected applyDeoptimizations(): void { this.deoptimized = true; for (const factoryVariable of this.factoryVariables.values()) { @@ -66,4 +90,16 @@ export default class JSXElement extends NodeBase { } } } + + render(code: MagicString, options: RenderOptions): void { + super.render(code, options); + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!jsx.preserve) { + // TODO import + code.overwrite(this.start, this.openingElement.name.start, `/*#__PURE__*/${jsx.factory}(`, { + contentOnly: true + }); + code.overwrite(this.openingElement.name.end, this.end, `, null)`, { contentOnly: true }); + } + } } diff --git a/src/utils/parseImportAttributes.ts b/src/utils/parseImportAttributes.ts index 2ec6fe227d7..0775a8ab02f 100644 --- a/src/utils/parseImportAttributes.ts +++ b/src/utils/parseImportAttributes.ts @@ -65,7 +65,9 @@ const getPropertyKey = (property: Property | SpreadElement | ImportAttribute): L ); }; -export function getAttributesFromImportExportDeclaration(attributes: ImportAttribute[]) { +export function getAttributesFromImportExportDeclaration( + attributes: ImportAttribute[] +): Record { return attributes?.length ? Object.fromEntries( attributes.map(assertion => [getPropertyKey(assertion), assertion.value.value]) diff --git a/test/form/samples/jsx/transpiles-react/_config.js b/test/form/samples/jsx/transpiles-react-jsx/_config.js similarity index 86% rename from test/form/samples/jsx/transpiles-react/_config.js rename to test/form/samples/jsx/transpiles-react-jsx/_config.js index 7dbf6431642..3c7f8e3b36a 100644 --- a/test/form/samples/jsx/transpiles-react/_config.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_config.js @@ -3,6 +3,6 @@ module.exports = defineTest({ description: 'transpiles JSX for react', options: { external: ['react'], - jsx: 'react' + jsx: 'react-jsx' } }); diff --git a/test/form/samples/jsx/transpiles-react-jsx/_expected.js b/test/form/samples/jsx/transpiles-react-jsx/_expected.js new file mode 100644 index 00000000000..b73397c4476 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-jsx/_expected.js @@ -0,0 +1,6 @@ +import { jsx } from 'react'; + +const Foo = () => {}; +const result = /*#__PURE__*/jsx(Foo, null); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-react/main.js b/test/form/samples/jsx/transpiles-react-jsx/main.js similarity index 56% rename from test/form/samples/jsx/transpiles-react/main.js rename to test/form/samples/jsx/transpiles-react-jsx/main.js index 6dc07da2a1d..69021f7fa8e 100644 --- a/test/form/samples/jsx/transpiles-react/main.js +++ b/test/form/samples/jsx/transpiles-react-jsx/main.js @@ -1,4 +1,4 @@ -import React from "react"; - const Foo = () => {}; export const result = ; +const jsx = 'wrong jsx' +console.log(jsx) diff --git a/test/form/samples/jsx/transpiles-react/_expected.js b/test/form/samples/jsx/transpiles-react/_expected.js deleted file mode 100644 index 1d99eacf9a9..00000000000 --- a/test/form/samples/jsx/transpiles-react/_expected.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from "react"; - -const Foo = () => {}; -const result = /*#__PURE__*/React.createElement(Foo, null); - -export { result }; From 0a978c30a9106bb48d3ce974baefcc504778c0f0 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Thu, 9 May 2024 21:37:58 +0200 Subject: [PATCH 18/62] Improve option and transpilation support --- src/ast/nodes/JSXElement.ts | 90 ++++++++----------- src/rollup/types.d.ts | 4 +- src/utils/options/mergeOptions.ts | 2 +- src/utils/options/normalizeInputOptions.ts | 4 +- src/utils/options/options.ts | 10 ++- .../jsx-preserve-react-conflict/_config.js | 8 -- .../jsx-preserve-react-conflict/_expected.js | 6 -- .../jsx/jsx-preserve-react-conflict/dep1.js | 4 - .../jsx/jsx-preserve-react-conflict/dep2.js | 4 - .../jsx/jsx-preserve-react-conflict/main.js | 4 - .../jsx/preserves-react-global/_config.js | 11 +++ .../_expected.js | 7 +- .../samples/jsx/preserves-react-global/jsx.js | 2 + .../main.js | 0 .../other1.js | 0 .../other2.js | 0 .../jsx/preserves-react-local/_config.js | 9 -- .../samples/jsx/preserves-react-local/jsx.js | 5 -- .../jsx/transpiles-react-global/_config.js | 10 +++ .../jsx/transpiles-react-global/_expected.js | 10 +++ .../jsx/transpiles-react-global/jsx.js | 2 + .../jsx/transpiles-react-global/main.js | 3 + .../jsx/transpiles-react-global/other1.js | 3 + .../jsx/transpiles-react-global/other2.js | 3 + .../jsx/transpiles-react-jsx/_expected.js | 14 ++- .../samples/jsx/transpiles-react-jsx/jsx.js | 2 + .../samples/jsx/transpiles-react-jsx/main.js | 7 +- .../jsx/transpiles-react-jsx/other1.js | 3 + .../jsx/transpiles-react-jsx/other2.js | 3 + .../samples/jsx/transpiles-react/_config.js | 8 ++ .../samples/jsx/transpiles-react/_expected.js | 12 +++ test/form/samples/jsx/transpiles-react/jsx.js | 2 + .../form/samples/jsx/transpiles-react/main.js | 3 + .../samples/jsx/transpiles-react/other1.js | 3 + .../samples/jsx/transpiles-react/other2.js | 3 + 35 files changed, 149 insertions(+), 112 deletions(-) delete mode 100644 test/form/samples/jsx/jsx-preserve-react-conflict/_config.js delete mode 100644 test/form/samples/jsx/jsx-preserve-react-conflict/_expected.js delete mode 100644 test/form/samples/jsx/jsx-preserve-react-conflict/dep1.js delete mode 100644 test/form/samples/jsx/jsx-preserve-react-conflict/dep2.js delete mode 100644 test/form/samples/jsx/jsx-preserve-react-conflict/main.js create mode 100644 test/form/samples/jsx/preserves-react-global/_config.js rename test/form/samples/jsx/{preserves-react-local => preserves-react-global}/_expected.js (57%) create mode 100644 test/form/samples/jsx/preserves-react-global/jsx.js rename test/form/samples/jsx/{preserves-react-local => preserves-react-global}/main.js (100%) rename test/form/samples/jsx/{preserves-react-local => preserves-react-global}/other1.js (100%) rename test/form/samples/jsx/{preserves-react-local => preserves-react-global}/other2.js (100%) delete mode 100644 test/form/samples/jsx/preserves-react-local/_config.js delete mode 100644 test/form/samples/jsx/preserves-react-local/jsx.js create mode 100644 test/form/samples/jsx/transpiles-react-global/_config.js create mode 100644 test/form/samples/jsx/transpiles-react-global/_expected.js create mode 100644 test/form/samples/jsx/transpiles-react-global/jsx.js create mode 100644 test/form/samples/jsx/transpiles-react-global/main.js create mode 100644 test/form/samples/jsx/transpiles-react-global/other1.js create mode 100644 test/form/samples/jsx/transpiles-react-global/other2.js create mode 100644 test/form/samples/jsx/transpiles-react-jsx/jsx.js create mode 100644 test/form/samples/jsx/transpiles-react-jsx/other1.js create mode 100644 test/form/samples/jsx/transpiles-react-jsx/other2.js create mode 100644 test/form/samples/jsx/transpiles-react/_config.js create mode 100644 test/form/samples/jsx/transpiles-react/_expected.js create mode 100644 test/form/samples/jsx/transpiles-react/jsx.js create mode 100644 test/form/samples/jsx/transpiles-react/main.js create mode 100644 test/form/samples/jsx/transpiles-react/other1.js create mode 100644 test/form/samples/jsx/transpiles-react/other2.js diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 5094fa0a969..e4438ca2615 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -24,26 +24,7 @@ export default class JSXElement extends NodeBase { | JSXElement | JSXFragment ) /* TODO | JSXSpreadChild */[]; - private factoryVariables = new Map(); - - bind() { - super.bind(); - const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - if (jsx.preserve) { - for (const name of jsx.factoryGlobals) { - this.factoryVariables.set(name, this.scope.findVariable(name)); - } - } else if (jsx.importSource) { - const factoryBaseName = jsx.factory.split('.')[0]; - this.factoryVariables.set( - factoryBaseName, - this.scope.context.getImportedJsxFactoryVariable(factoryBaseName, this.start) - ); - } else { - // TODO handle non-imported - throw new Error('TODO'); - } - } + private factoryVariable: Variable | null = null; include( context: InclusionContext, @@ -52,24 +33,31 @@ export default class JSXElement extends NodeBase { ): void { if (!this.deoptimized) this.applyDeoptimizations(); if (!this.included) { - const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - if (jsx.preserve) { - // TODO can we rework this so that we throw when different JSX elements would use different React variables? - for (const [name, factoryVariable] of this.factoryVariables) { - // This pretends we are accessing an included global variable of the same name - const globalVariable = this.scope.findGlobal(name); - globalVariable.include(); - // This excludes this variable from renaming - factoryVariable.globalName = name; - this.scope.context.includeVariableInModule(factoryVariable); + const { factory, importSource, preserve } = this.scope.context.options + .jsx as NormalizedJsxOptions; + if (factory != null) { + const [baseName, nestedName] = factory.split('.'); + if (importSource) { + this.factoryVariable = this.scope.context.getImportedJsxFactoryVariable( + nestedName ? 'default' : baseName, + this.start + ); + if (preserve) { + // This pretends we are accessing an included global variable of the same name + const globalVariable = this.scope.findGlobal(baseName); + globalVariable.include(); + // This excludes this variable from renaming + this.factoryVariable.globalName = baseName; + } + } else { + this.factoryVariable = this.scope.findGlobal(baseName); } - } else if (jsx.importSource) { - for (const factoryVariable of this.factoryVariables.values()) { - this.scope.context.includeVariableInModule(factoryVariable); + this.scope.context.includeVariableInModule(this.factoryVariable); + if (this.factoryVariable instanceof LocalVariable) { + this.factoryVariable.consolidateInitializers(); + this.factoryVariable.addUsedPlace(this); + this.scope.context.requestTreeshakingPass(); } - } else { - // TODO handle non-imported - throw new Error('TODO'); } } super.include(context, includeChildrenRecursively, options); @@ -80,25 +68,21 @@ export default class JSXElement extends NodeBase { this.scope.context.addJsx(); } - protected applyDeoptimizations(): void { - this.deoptimized = true; - for (const factoryVariable of this.factoryVariables.values()) { - if (factoryVariable instanceof LocalVariable) { - factoryVariable.consolidateInitializers(); - factoryVariable.addUsedPlace(this); - this.scope.context.requestTreeshakingPass(); - } - } - } - render(code: MagicString, options: RenderOptions): void { super.render(code, options); - const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!jsx.preserve) { - // TODO import - code.overwrite(this.start, this.openingElement.name.start, `/*#__PURE__*/${jsx.factory}(`, { - contentOnly: true - }); + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + const { factory, preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + const [, ...nestedName] = factory.split('.'); + code.overwrite( + this.start, + this.openingElement.name.start, + `/*#__PURE__*/${[this.factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, + { contentOnly: true } + ); code.overwrite(this.openingElement.name.end, this.end, `, null)`, { contentOnly: true }); } } diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index baf0b253c2a..a9ffa5ddd0c 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -535,7 +535,9 @@ interface NormalizedJsxTranspileOptions { } interface NormalizedJsxPreserveOptions { - factoryGlobals: string[]; + factory: string | null; + fragmentFactory: string | null; + importSource: string | null; preserve: true; } diff --git a/src/utils/options/mergeOptions.ts b/src/utils/options/mergeOptions.ts index 26e6e32e4f6..a1253f29a76 100644 --- a/src/utils/options/mergeOptions.ts +++ b/src/utils/options/mergeOptions.ts @@ -140,7 +140,7 @@ function mergeInputOptions( overrides, 'jsx', ['preserve'], - objectifyOptionWithPresets(treeshakePresets, 'jsx', URL_JSX, 'false, "preserve", ') + objectifyOptionWithPresets(treeshakePresets, 'jsx', URL_JSX, 'false, ') ), logLevel: getOption('logLevel'), makeAbsoluteExternalsRelative: getOption('makeAbsoluteExternalsRelative'), diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index 41f21afd643..c2aac4055a7 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -128,7 +128,9 @@ const getJsx = (config: InputOptions): NormalizedInputOptions['jsx'] => { ); return configWithPreset.preserve ? { - factoryGlobals: configWithPreset.factoryGlobals || EMPTY_ARRAY, + factory: configWithPreset.factory || null, + fragmentFactory: configWithPreset.fragmentFactory || null, + importSource: configWithPreset.importSource || null, preserve: true } : { diff --git a/src/utils/options/options.ts b/src/utils/options/options.ts index 46897a424ef..c6117907b86 100644 --- a/src/utils/options/options.ts +++ b/src/utils/options/options.ts @@ -141,17 +141,21 @@ export const jsxPresets: { [key in NonNullable['preset']>]: NormalizedJsxOptions; } = { preserve: { - factoryGlobals: EMPTY_ARRAY as never[], + factory: null, + fragmentFactory: null, + importSource: null, preserve: true }, 'preserve-react': { - factoryGlobals: ['React'], + factory: 'React.createElement', + fragmentFactory: 'React.Fragment', + importSource: 'react', preserve: true }, react: { factory: 'React.createElement', fragmentFactory: 'React.Fragment', - importSource: null, + importSource: 'react', preserve: false }, 'react-jsx': { diff --git a/test/form/samples/jsx/jsx-preserve-react-conflict/_config.js b/test/form/samples/jsx/jsx-preserve-react-conflict/_config.js deleted file mode 100644 index 3130327d73e..00000000000 --- a/test/form/samples/jsx/jsx-preserve-react-conflict/_config.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = defineTest({ - // TODO This should actually be a function test that throws - solo: true, - description: 'this ensures the local React variable is not renamed when preserving JSX output', - options: { - jsx: 'preserve' - } -}); diff --git a/test/form/samples/jsx/jsx-preserve-react-conflict/_expected.js b/test/form/samples/jsx/jsx-preserve-react-conflict/_expected.js deleted file mode 100644 index 2f1d81a4a65..00000000000 --- a/test/form/samples/jsx/jsx-preserve-react-conflict/_expected.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; - -const Foo = () => {}; -const result = ; - -export { result }; diff --git a/test/form/samples/jsx/jsx-preserve-react-conflict/dep1.js b/test/form/samples/jsx/jsx-preserve-react-conflict/dep1.js deleted file mode 100644 index 3dd027858b4..00000000000 --- a/test/form/samples/jsx/jsx-preserve-react-conflict/dep1.js +++ /dev/null @@ -1,4 +0,0 @@ -const React = 'React1'; - -const Foo = () => {}; -export const foo1 = ; diff --git a/test/form/samples/jsx/jsx-preserve-react-conflict/dep2.js b/test/form/samples/jsx/jsx-preserve-react-conflict/dep2.js deleted file mode 100644 index 2c12b32afd1..00000000000 --- a/test/form/samples/jsx/jsx-preserve-react-conflict/dep2.js +++ /dev/null @@ -1,4 +0,0 @@ -const React = 'React2'; - -const Foo = () => {}; -export const foo2 = ; diff --git a/test/form/samples/jsx/jsx-preserve-react-conflict/main.js b/test/form/samples/jsx/jsx-preserve-react-conflict/main.js deleted file mode 100644 index 77f3bfd706f..00000000000 --- a/test/form/samples/jsx/jsx-preserve-react-conflict/main.js +++ /dev/null @@ -1,4 +0,0 @@ -import { foo1 } from "./dep1"; -import { foo2 } from "./dep2"; - -console.log(foo1, foo2); diff --git a/test/form/samples/jsx/preserves-react-global/_config.js b/test/form/samples/jsx/preserves-react-global/_config.js new file mode 100644 index 00000000000..e80ae4aeeec --- /dev/null +++ b/test/form/samples/jsx/preserves-react-global/_config.js @@ -0,0 +1,11 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves React variable when preserving JSX output', + options: { + jsx: { + factory: 'React.createElement', + fragmentFactory: 'React.Fragment', + preserve: true + } + } +}); diff --git a/test/form/samples/jsx/preserves-react-local/_expected.js b/test/form/samples/jsx/preserves-react-global/_expected.js similarity index 57% rename from test/form/samples/jsx/preserves-react-local/_expected.js rename to test/form/samples/jsx/preserves-react-global/_expected.js index 9ec83e05875..62f669e6899 100644 --- a/test/form/samples/jsx/preserves-react-local/_expected.js +++ b/test/form/samples/jsx/preserves-react-global/_expected.js @@ -1,10 +1,7 @@ -import theReact from 'react'; - const Foo$2 = () => {}; -const React$3 = () => {}; -console.log(Foo$2, React$3); +const React$2 = () => {}; +console.log(Foo$2, React$2); -const React = theReact; const Foo$1 = () => {}; console.log(); diff --git a/test/form/samples/jsx/preserves-react-global/jsx.js b/test/form/samples/jsx/preserves-react-global/jsx.js new file mode 100644 index 00000000000..4b5671bbbac --- /dev/null +++ b/test/form/samples/jsx/preserves-react-global/jsx.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); diff --git a/test/form/samples/jsx/preserves-react-local/main.js b/test/form/samples/jsx/preserves-react-global/main.js similarity index 100% rename from test/form/samples/jsx/preserves-react-local/main.js rename to test/form/samples/jsx/preserves-react-global/main.js diff --git a/test/form/samples/jsx/preserves-react-local/other1.js b/test/form/samples/jsx/preserves-react-global/other1.js similarity index 100% rename from test/form/samples/jsx/preserves-react-local/other1.js rename to test/form/samples/jsx/preserves-react-global/other1.js diff --git a/test/form/samples/jsx/preserves-react-local/other2.js b/test/form/samples/jsx/preserves-react-global/other2.js similarity index 100% rename from test/form/samples/jsx/preserves-react-local/other2.js rename to test/form/samples/jsx/preserves-react-global/other2.js diff --git a/test/form/samples/jsx/preserves-react-local/_config.js b/test/form/samples/jsx/preserves-react-local/_config.js deleted file mode 100644 index 8e99dce7a67..00000000000 --- a/test/form/samples/jsx/preserves-react-local/_config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = defineTest({ - solo: true, - description: 'preserves local React variable when preserving JSX output', - options: { - external: ['react'], - jsx: 'preserve-react' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] -}); diff --git a/test/form/samples/jsx/preserves-react-local/jsx.js b/test/form/samples/jsx/preserves-react-local/jsx.js deleted file mode 100644 index 44e19d36489..00000000000 --- a/test/form/samples/jsx/preserves-react-local/jsx.js +++ /dev/null @@ -1,5 +0,0 @@ -import theReact from "react"; - -const React = theReact; -const Foo = () => {}; -console.log(); diff --git a/test/form/samples/jsx/transpiles-react-global/_config.js b/test/form/samples/jsx/transpiles-react-global/_config.js new file mode 100644 index 00000000000..ead07d867b4 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-global/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX for react', + options: { + jsx: { + factory: 'React.createElement', + fragmentFactory: 'React.Fragment' + } + } +}); diff --git a/test/form/samples/jsx/transpiles-react-global/_expected.js b/test/form/samples/jsx/transpiles-react-global/_expected.js new file mode 100644 index 00000000000..0dab4df904b --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-global/_expected.js @@ -0,0 +1,10 @@ +const Foo$2 = 'wrong Foo 1'; +const React$2 = 'wrong React 1'; +console.log(Foo$2, React$2); + +const Foo$1 = () => {}; +console.log(/*#__PURE__*/React.createElement(Foo$1, null)); + +const Foo = 'wrong Foo 2'; +const React$1 = 'wrong React 2'; +console.log(Foo, React$1); diff --git a/test/form/samples/jsx/transpiles-react-global/jsx.js b/test/form/samples/jsx/transpiles-react-global/jsx.js new file mode 100644 index 00000000000..4b5671bbbac --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-global/jsx.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); diff --git a/test/form/samples/jsx/transpiles-react-global/main.js b/test/form/samples/jsx/transpiles-react-global/main.js new file mode 100644 index 00000000000..dfccae85926 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-global/main.js @@ -0,0 +1,3 @@ +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/transpiles-react-global/other1.js b/test/form/samples/jsx/transpiles-react-global/other1.js new file mode 100644 index 00000000000..7b5145191de --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-global/other1.js @@ -0,0 +1,3 @@ +const Foo = 'wrong Foo 1'; +const React = 'wrong React 1'; +console.log(Foo, React); diff --git a/test/form/samples/jsx/transpiles-react-global/other2.js b/test/form/samples/jsx/transpiles-react-global/other2.js new file mode 100644 index 00000000000..10b37745be6 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-global/other2.js @@ -0,0 +1,3 @@ +const Foo = 'wrong Foo 2'; +const React = 'wrong React 2'; +console.log(Foo, React); diff --git a/test/form/samples/jsx/transpiles-react-jsx/_expected.js b/test/form/samples/jsx/transpiles-react-jsx/_expected.js index b73397c4476..706117213bb 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_expected.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_expected.js @@ -1,6 +1,12 @@ -import { jsx } from 'react'; +import { jsx as jsx$2 } from 'react'; -const Foo = () => {}; -const result = /*#__PURE__*/jsx(Foo, null); +const Foo$2 = 'wrong Foo 1'; +const jsx$1 = 'wrong jsx 1'; +console.log(Foo$2, jsx$1); -export { result }; +const Foo$1 = () => {}; +console.log(/*#__PURE__*/jsx$2(Foo$1, null)); + +const Foo = 'wrong Foo 2'; +const jsx = 'wrong jsx 2'; +console.log(Foo, jsx); diff --git a/test/form/samples/jsx/transpiles-react-jsx/jsx.js b/test/form/samples/jsx/transpiles-react-jsx/jsx.js new file mode 100644 index 00000000000..4b5671bbbac --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-jsx/jsx.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); diff --git a/test/form/samples/jsx/transpiles-react-jsx/main.js b/test/form/samples/jsx/transpiles-react-jsx/main.js index 69021f7fa8e..dfccae85926 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/main.js +++ b/test/form/samples/jsx/transpiles-react-jsx/main.js @@ -1,4 +1,3 @@ -const Foo = () => {}; -export const result = ; -const jsx = 'wrong jsx' -console.log(jsx) +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/transpiles-react-jsx/other1.js b/test/form/samples/jsx/transpiles-react-jsx/other1.js new file mode 100644 index 00000000000..8f9e29e5f2c --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-jsx/other1.js @@ -0,0 +1,3 @@ +const Foo = 'wrong Foo 1'; +const jsx = 'wrong jsx 1'; +console.log(Foo, jsx); diff --git a/test/form/samples/jsx/transpiles-react-jsx/other2.js b/test/form/samples/jsx/transpiles-react-jsx/other2.js new file mode 100644 index 00000000000..fe345b1ba6b --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-jsx/other2.js @@ -0,0 +1,3 @@ +const Foo = 'wrong Foo 2'; +const jsx = 'wrong jsx 2'; +console.log(Foo, jsx); diff --git a/test/form/samples/jsx/transpiles-react/_config.js b/test/form/samples/jsx/transpiles-react/_config.js new file mode 100644 index 00000000000..7dbf6431642 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX for react', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-react/_expected.js b/test/form/samples/jsx/transpiles-react/_expected.js new file mode 100644 index 00000000000..c588a702040 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react/_expected.js @@ -0,0 +1,12 @@ +import react from 'react'; + +const Foo$2 = 'wrong Foo 1'; +const React$1 = 'wrong React 1'; +console.log(Foo$2, React$1); + +const Foo$1 = () => {}; +console.log(/*#__PURE__*/react.createElement(Foo$1, null)); + +const Foo = 'wrong Foo 2'; +const React = 'wrong React 2'; +console.log(Foo, React); diff --git a/test/form/samples/jsx/transpiles-react/jsx.js b/test/form/samples/jsx/transpiles-react/jsx.js new file mode 100644 index 00000000000..4b5671bbbac --- /dev/null +++ b/test/form/samples/jsx/transpiles-react/jsx.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); diff --git a/test/form/samples/jsx/transpiles-react/main.js b/test/form/samples/jsx/transpiles-react/main.js new file mode 100644 index 00000000000..dfccae85926 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react/main.js @@ -0,0 +1,3 @@ +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/transpiles-react/other1.js b/test/form/samples/jsx/transpiles-react/other1.js new file mode 100644 index 00000000000..7b5145191de --- /dev/null +++ b/test/form/samples/jsx/transpiles-react/other1.js @@ -0,0 +1,3 @@ +const Foo = 'wrong Foo 1'; +const React = 'wrong React 1'; +console.log(Foo, React); diff --git a/test/form/samples/jsx/transpiles-react/other2.js b/test/form/samples/jsx/transpiles-react/other2.js new file mode 100644 index 00000000000..10b37745be6 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react/other2.js @@ -0,0 +1,3 @@ +const Foo = 'wrong Foo 2'; +const React = 'wrong React 2'; +console.log(Foo, React); From c49be1b1efa345435b4ae48d278c3134e3169bff Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 10 May 2024 07:19:46 +0200 Subject: [PATCH 19/62] Handle missing jsx factory --- src/Module.ts | 6 ++-- src/utils/logs.ts | 13 +++++++ .../jsx/preserves-jsx-child/_config.js | 3 +- .../jsx/preserves-jsx-closing/_config.js | 3 +- .../preserves-jsx-empty-expression/_config.js | 3 +- .../_config.js | 3 +- .../jsx/preserves-jsx-fragment/_config.js | 3 +- .../samples/jsx/preserves-jsx-text/_config.js | 3 +- .../preserves-jsx-with-attributes/_config.js | 3 +- .../jsx/preserves-react-internal/_config.js | 12 +++++++ .../jsx/preserves-react-internal/_expected.js | 16 +++++++++ .../jsx/preserves-react-internal/jsx.js | 2 ++ .../jsx/preserves-react-internal/main.js | 3 ++ .../jsx/preserves-react-internal/other1.js | 3 ++ .../jsx/preserves-react-internal/other2.js | 3 ++ .../jsx/preserves-react-internal/react.js | 5 +++ .../samples/jsx/preserves-react/_config.js | 3 +- .../jsx/transpiles-react-internal/_config.js | 11 ++++++ .../transpiles-react-internal/_expected.js | 16 +++++++++ .../jsx/transpiles-react-internal/jsx.js | 2 ++ .../jsx/transpiles-react-internal/main.js | 3 ++ .../jsx/transpiles-react-internal/other1.js | 3 ++ .../jsx/transpiles-react-internal/other2.js | 3 ++ .../jsx/transpiles-react-internal/react.js | 5 +++ .../samples/jsx/missing-jsx-export/_config.js | 35 +++++++++++++++++++ .../jsx/missing-jsx-export/_expected.js | 16 +++++++++ .../samples/jsx/missing-jsx-export/main.js | 2 ++ .../samples/jsx/missing-jsx-export/react.js | 1 + 28 files changed, 165 insertions(+), 19 deletions(-) create mode 100644 test/form/samples/jsx/preserves-react-internal/_config.js create mode 100644 test/form/samples/jsx/preserves-react-internal/_expected.js create mode 100644 test/form/samples/jsx/preserves-react-internal/jsx.js create mode 100644 test/form/samples/jsx/preserves-react-internal/main.js create mode 100644 test/form/samples/jsx/preserves-react-internal/other1.js create mode 100644 test/form/samples/jsx/preserves-react-internal/other2.js create mode 100644 test/form/samples/jsx/preserves-react-internal/react.js create mode 100644 test/form/samples/jsx/transpiles-react-internal/_config.js create mode 100644 test/form/samples/jsx/transpiles-react-internal/_expected.js create mode 100644 test/form/samples/jsx/transpiles-react-internal/jsx.js create mode 100644 test/form/samples/jsx/transpiles-react-internal/main.js create mode 100644 test/form/samples/jsx/transpiles-react-internal/other1.js create mode 100644 test/form/samples/jsx/transpiles-react-internal/other2.js create mode 100644 test/form/samples/jsx/transpiles-react-internal/react.js create mode 100644 test/function/samples/jsx/missing-jsx-export/_config.js create mode 100644 test/function/samples/jsx/missing-jsx-export/_expected.js create mode 100644 test/function/samples/jsx/missing-jsx-export/main.js create mode 100644 test/function/samples/jsx/missing-jsx-export/react.js diff --git a/src/Module.ts b/src/Module.ts index 326154a9607..19c984959c2 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -71,6 +71,7 @@ import { logInvalidSourcemapForError, logMissingEntryExport, logMissingExport, + logMissingJsxExport, logModuleParseError, logNamespaceConflict, logRedeclarationError, @@ -1155,7 +1156,7 @@ export default class Module { private addJsx(): void { const jsx = this.options.jsx as NormalizedJsxOptions; - if (!jsx.preserve && jsx.importSource && !this.sourcesWithAttributes.has(jsx.importSource)) { + if (jsx.importSource && !this.sourcesWithAttributes.has(jsx.importSource)) { this.sourcesWithAttributes.set(jsx.importSource, EMPTY_OBJECT); } } @@ -1252,8 +1253,7 @@ export default class Module { const module = this.graph.modulesById.get(id)!; const [variable] = module.getVariableForExportName(baseName); if (!variable) { - // TODO proper error - throw new Error('TODO ' + nodeStart); + return this.error(logMissingJsxExport(baseName, id, this.id), nodeStart); } return variable; } diff --git a/src/utils/logs.ts b/src/utils/logs.ts index 2274103f6e8..7c09d04a16f 100644 --- a/src/utils/logs.ts +++ b/src/utils/logs.ts @@ -18,6 +18,7 @@ import { URL_AVOIDING_EVAL, URL_BUNDLE_CONFIG_AS_CJS, URL_CONFIGURATION_FILES, + URL_JSX, URL_NAME_IS_NOT_EXPORTED, URL_OUTPUT_DIR, URL_OUTPUT_EXPORTS, @@ -154,6 +155,7 @@ const ADDON_ERROR = 'ADDON_ERROR', MISSING_EXTERNAL_CONFIG = 'MISSING_EXTERNAL_CONFIG', MISSING_GLOBAL_NAME = 'MISSING_GLOBAL_NAME', MISSING_IMPLICIT_DEPENDANT = 'MISSING_IMPLICIT_DEPENDANT', + MISSING_JSX_EXPORT = 'MISSING_JSX_EXPORT', MISSING_NAME_OPTION_FOR_IIFE_EXPORT = 'MISSING_NAME_OPTION_FOR_IIFE_EXPORT', MISSING_NODE_BUILTINS = 'MISSING_NODE_BUILTINS', MISSING_OPTION = 'MISSING_OPTION', @@ -770,6 +772,17 @@ export function logImplicitDependantIsNotIncluded(module: Module): RollupLog { }; } +export function logMissingJsxExport(name: string, exporter: string, importer: string): RollupLog { + return { + code: MISSING_JSX_EXPORT, + exporter, + id: importer, + message: `Export "${name}" is not defined in module "${relativeId(exporter)}" even though it is needed in "${relativeId(importer)}" to provide JSX syntax. Please check your "jsx" option.`, + names: [name], + url: getRollupUrl(URL_JSX) + }; +} + export function logMissingNameOptionForIifeExport(): RollupLog { return { code: MISSING_NAME_OPTION_FOR_IIFE_EXPORT, diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js index 78de66a33bd..deba7dd3240 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -4,6 +4,5 @@ module.exports = defineTest({ options: { external: ['react'], jsx: 'preserve' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] + } }); diff --git a/test/form/samples/jsx/preserves-jsx-closing/_config.js b/test/form/samples/jsx/preserves-jsx-closing/_config.js index 78de66a33bd..deba7dd3240 100644 --- a/test/form/samples/jsx/preserves-jsx-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-closing/_config.js @@ -4,6 +4,5 @@ module.exports = defineTest({ options: { external: ['react'], jsx: 'preserve' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] + } }); diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js index 78de66a33bd..deba7dd3240 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js @@ -4,6 +4,5 @@ module.exports = defineTest({ options: { external: ['react'], jsx: 'preserve' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] + } }); diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js index 78de66a33bd..deba7dd3240 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js @@ -4,6 +4,5 @@ module.exports = defineTest({ options: { external: ['react'], jsx: 'preserve' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] + } }); diff --git a/test/form/samples/jsx/preserves-jsx-fragment/_config.js b/test/form/samples/jsx/preserves-jsx-fragment/_config.js index 78de66a33bd..deba7dd3240 100644 --- a/test/form/samples/jsx/preserves-jsx-fragment/_config.js +++ b/test/form/samples/jsx/preserves-jsx-fragment/_config.js @@ -4,6 +4,5 @@ module.exports = defineTest({ options: { external: ['react'], jsx: 'preserve' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] + } }); diff --git a/test/form/samples/jsx/preserves-jsx-text/_config.js b/test/form/samples/jsx/preserves-jsx-text/_config.js index 78de66a33bd..deba7dd3240 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_config.js +++ b/test/form/samples/jsx/preserves-jsx-text/_config.js @@ -4,6 +4,5 @@ module.exports = defineTest({ options: { external: ['react'], jsx: 'preserve' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] + } }); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js b/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js index de881e8ad62..ffe19c7a1fa 100644 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js @@ -4,6 +4,5 @@ module.exports = defineTest({ options: { external: ['react'], jsx: 'preserve' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] + } }); diff --git a/test/form/samples/jsx/preserves-react-internal/_config.js b/test/form/samples/jsx/preserves-react-internal/_config.js new file mode 100644 index 00000000000..bf4884466a2 --- /dev/null +++ b/test/form/samples/jsx/preserves-react-internal/_config.js @@ -0,0 +1,12 @@ +const path = require('node:path'); + +module.exports = defineTest({ + solo: true, + description: 'preserves internal React variable when preserving JSX output', + options: { + jsx: { + importSource: path.join(__dirname, 'react.js'), + preset: 'preserve-react' + } + } +}); diff --git a/test/form/samples/jsx/preserves-react-internal/_expected.js b/test/form/samples/jsx/preserves-react-internal/_expected.js new file mode 100644 index 00000000000..1d4e574bb0e --- /dev/null +++ b/test/form/samples/jsx/preserves-react-internal/_expected.js @@ -0,0 +1,16 @@ +const Foo$2 = () => {}; +const React$2 = () => {}; +console.log(Foo$2, React$2); + +var React = { + createElement() { + console.log('createElement'); + } +}; + +const Foo$1 = () => {}; +console.log(); + +const Foo = () => {}; +const React$1 = () => {}; +console.log(Foo, React$1); diff --git a/test/form/samples/jsx/preserves-react-internal/jsx.js b/test/form/samples/jsx/preserves-react-internal/jsx.js new file mode 100644 index 00000000000..4b5671bbbac --- /dev/null +++ b/test/form/samples/jsx/preserves-react-internal/jsx.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); diff --git a/test/form/samples/jsx/preserves-react-internal/main.js b/test/form/samples/jsx/preserves-react-internal/main.js new file mode 100644 index 00000000000..dfccae85926 --- /dev/null +++ b/test/form/samples/jsx/preserves-react-internal/main.js @@ -0,0 +1,3 @@ +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/preserves-react-internal/other1.js b/test/form/samples/jsx/preserves-react-internal/other1.js new file mode 100644 index 00000000000..dc7480c221c --- /dev/null +++ b/test/form/samples/jsx/preserves-react-internal/other1.js @@ -0,0 +1,3 @@ +const Foo = () => {}; +const React = () => {}; +console.log(Foo, React); diff --git a/test/form/samples/jsx/preserves-react-internal/other2.js b/test/form/samples/jsx/preserves-react-internal/other2.js new file mode 100644 index 00000000000..dc7480c221c --- /dev/null +++ b/test/form/samples/jsx/preserves-react-internal/other2.js @@ -0,0 +1,3 @@ +const Foo = () => {}; +const React = () => {}; +console.log(Foo, React); diff --git a/test/form/samples/jsx/preserves-react-internal/react.js b/test/form/samples/jsx/preserves-react-internal/react.js new file mode 100644 index 00000000000..62d36813017 --- /dev/null +++ b/test/form/samples/jsx/preserves-react-internal/react.js @@ -0,0 +1,5 @@ +export default { + createElement() { + console.log('createElement'); + } +}; diff --git a/test/form/samples/jsx/preserves-react/_config.js b/test/form/samples/jsx/preserves-react/_config.js index 5ce9b42fbd9..9f7101ac6f1 100644 --- a/test/form/samples/jsx/preserves-react/_config.js +++ b/test/form/samples/jsx/preserves-react/_config.js @@ -4,6 +4,5 @@ module.exports = defineTest({ options: { external: ['react'], jsx: 'preserve-react' - }, - expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'] + } }); diff --git a/test/form/samples/jsx/transpiles-react-internal/_config.js b/test/form/samples/jsx/transpiles-react-internal/_config.js new file mode 100644 index 00000000000..0e8b9fe0132 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-internal/_config.js @@ -0,0 +1,11 @@ +const path = require('node:path'); +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX for react', + options: { + jsx: { + importSource: path.join(__dirname, 'react.js'), + preset: 'react' + } + } +}); diff --git a/test/form/samples/jsx/transpiles-react-internal/_expected.js b/test/form/samples/jsx/transpiles-react-internal/_expected.js new file mode 100644 index 00000000000..0e6ceaa7ccd --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-internal/_expected.js @@ -0,0 +1,16 @@ +const Foo$2 = 'wrong Foo 1'; +const React$1 = 'wrong React 1'; +console.log(Foo$2, React$1); + +var react = { + createElement() { + console.log('createElement'); + } +}; + +const Foo$1 = () => {}; +console.log(/*#__PURE__*/react.createElement(Foo$1, null)); + +const Foo = 'wrong Foo 2'; +const React = 'wrong React 2'; +console.log(Foo, React); diff --git a/test/form/samples/jsx/transpiles-react-internal/jsx.js b/test/form/samples/jsx/transpiles-react-internal/jsx.js new file mode 100644 index 00000000000..4b5671bbbac --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-internal/jsx.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); diff --git a/test/form/samples/jsx/transpiles-react-internal/main.js b/test/form/samples/jsx/transpiles-react-internal/main.js new file mode 100644 index 00000000000..dfccae85926 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-internal/main.js @@ -0,0 +1,3 @@ +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/transpiles-react-internal/other1.js b/test/form/samples/jsx/transpiles-react-internal/other1.js new file mode 100644 index 00000000000..7b5145191de --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-internal/other1.js @@ -0,0 +1,3 @@ +const Foo = 'wrong Foo 1'; +const React = 'wrong React 1'; +console.log(Foo, React); diff --git a/test/form/samples/jsx/transpiles-react-internal/other2.js b/test/form/samples/jsx/transpiles-react-internal/other2.js new file mode 100644 index 00000000000..10b37745be6 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-internal/other2.js @@ -0,0 +1,3 @@ +const Foo = 'wrong Foo 2'; +const React = 'wrong React 2'; +console.log(Foo, React); diff --git a/test/form/samples/jsx/transpiles-react-internal/react.js b/test/form/samples/jsx/transpiles-react-internal/react.js new file mode 100644 index 00000000000..62d36813017 --- /dev/null +++ b/test/form/samples/jsx/transpiles-react-internal/react.js @@ -0,0 +1,5 @@ +export default { + createElement() { + console.log('createElement'); + } +}; diff --git a/test/function/samples/jsx/missing-jsx-export/_config.js b/test/function/samples/jsx/missing-jsx-export/_config.js new file mode 100644 index 00000000000..d62a8af710e --- /dev/null +++ b/test/function/samples/jsx/missing-jsx-export/_config.js @@ -0,0 +1,35 @@ +const path = require('node:path'); + +const ID_REACT = path.join(__dirname, 'react.js'); +const ID_MAIN = path.join(__dirname, 'main.js'); + +module.exports = defineTest({ + solo: true, + description: 'throws when the JSX factory is not exported', + options: { + jsx: { + importSource: ID_REACT, + preset: 'react-jsx' + } + }, + error: { + code: 'MISSING_JSX_EXPORT', + exporter: ID_REACT, + frame: ` + 1: const Foo = () => {}; + 2: console.log(); + ^`, + id: ID_MAIN, + loc: { + column: 12, + file: ID_MAIN, + line: 2 + }, + message: + 'main.js (2:12): Export "jsx" is not defined in module "react.js" even though it is needed in "main.js" to provide JSX syntax. Please check your "jsx" option.', + names: ['jsx'], + pos: 34, + url: 'https://rollupjs.org/configuration-options/#jsx', + watchFiles: [ID_MAIN, ID_REACT] + } +}); diff --git a/test/function/samples/jsx/missing-jsx-export/_expected.js b/test/function/samples/jsx/missing-jsx-export/_expected.js new file mode 100644 index 00000000000..0e6ceaa7ccd --- /dev/null +++ b/test/function/samples/jsx/missing-jsx-export/_expected.js @@ -0,0 +1,16 @@ +const Foo$2 = 'wrong Foo 1'; +const React$1 = 'wrong React 1'; +console.log(Foo$2, React$1); + +var react = { + createElement() { + console.log('createElement'); + } +}; + +const Foo$1 = () => {}; +console.log(/*#__PURE__*/react.createElement(Foo$1, null)); + +const Foo = 'wrong Foo 2'; +const React = 'wrong React 2'; +console.log(Foo, React); diff --git a/test/function/samples/jsx/missing-jsx-export/main.js b/test/function/samples/jsx/missing-jsx-export/main.js new file mode 100644 index 00000000000..4b5671bbbac --- /dev/null +++ b/test/function/samples/jsx/missing-jsx-export/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); diff --git a/test/function/samples/jsx/missing-jsx-export/react.js b/test/function/samples/jsx/missing-jsx-export/react.js new file mode 100644 index 00000000000..0245cde6d1a --- /dev/null +++ b/test/function/samples/jsx/missing-jsx-export/react.js @@ -0,0 +1 @@ +export default 'actually we need jsx'; From bca5eab408a626b316fd7cdbd885a8089619a27c Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 11 May 2024 06:34:35 +0200 Subject: [PATCH 20/62] Add additional tests and support expressions --- src/ast/nodes/JSXElement.ts | 19 +++++++++++++++++-- src/ast/nodes/JSXExpressionContainer.ts | 12 ++++++++++++ src/utils/options/options.ts | 2 +- .../jsx/preserves-jsx-child/_config.js | 2 +- .../jsx/preserves-jsx-closing/_config.js | 2 +- .../_expected.js | 4 ---- .../main.js | 2 -- .../_config.js | 2 +- .../jsx/preserves-jsx-expression/_expected.js | 13 +++++++++++++ .../jsx/preserves-jsx-expression/dep1.js | 2 ++ .../jsx/preserves-jsx-expression/dep2.js | 2 ++ .../jsx/preserves-jsx-expression/dep3.js | 2 ++ .../jsx/preserves-jsx-expression/main.js | 6 ++++++ .../_config.js | 2 +- .../_expected.js | 0 .../main.js | 0 .../samples/jsx/preserves-jsx-text/_config.js | 2 +- .../samples/jsx/preserves-jsx-text/main.js | 2 +- .../jsx/transpiles-jsx-child/_config.js | 8 ++++++++ .../jsx/transpiles-jsx-child/_expected.js | 6 ++++++ .../samples/jsx/transpiles-jsx-child/main.js | 2 ++ .../jsx/transpiles-jsx-closing/_config.js | 8 ++++++++ .../jsx/transpiles-jsx-closing/_expected.js | 6 ++++++ .../jsx/transpiles-jsx-closing/main.js | 2 ++ .../_config.js | 8 ++++++++ .../_expected.js | 6 ++++++ .../transpiles-jsx-empty-expression/main.js | 2 ++ .../jsx/transpiles-jsx-expression/_config.js | 8 ++++++++ .../transpiles-jsx-expression/_expected.js | 15 +++++++++++++++ .../jsx/transpiles-jsx-expression/dep1.js | 2 ++ .../jsx/transpiles-jsx-expression/dep2.js | 2 ++ .../jsx/transpiles-jsx-expression/dep3.js | 2 ++ .../jsx/transpiles-jsx-expression/main.js | 6 ++++++ .../jsx/transpiles-jsx-fragment/_config.js | 8 ++++++++ .../jsx/transpiles-jsx-fragment/_expected.js | 6 ++++++ .../jsx/transpiles-jsx-fragment/main.js | 2 ++ .../transpiles-jsx-self-closing/_config.js | 8 ++++++++ .../transpiles-jsx-self-closing/_expected.js | 6 ++++++ .../jsx/transpiles-jsx-self-closing/main.js | 2 ++ .../jsx/transpiles-jsx-text/_config.js | 8 ++++++++ .../jsx/transpiles-jsx-text/_expected.js | 6 ++++++ .../samples/jsx/transpiles-jsx-text/main.js | 2 ++ .../transpiles-jsx-with-attributes/_config.js | 8 ++++++++ .../_expected.js | 10 ++++++++++ .../transpiles-jsx-with-attributes/main.js | 2 ++ .../jsx/transpiles-react-jsx/_expected.js | 2 +- 46 files changed, 213 insertions(+), 16 deletions(-) delete mode 100644 test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js delete mode 100644 test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js rename test/form/samples/jsx/{preserves-jsx-empty-literal-expression => preserves-jsx-expression}/_config.js (70%) create mode 100644 test/form/samples/jsx/preserves-jsx-expression/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-expression/dep1.js create mode 100644 test/form/samples/jsx/preserves-jsx-expression/dep2.js create mode 100644 test/form/samples/jsx/preserves-jsx-expression/dep3.js create mode 100644 test/form/samples/jsx/preserves-jsx-expression/main.js rename test/form/samples/jsx/{preserves-jsx => preserves-jsx-self-closing}/_config.js (60%) rename test/form/samples/jsx/{preserves-jsx => preserves-jsx-self-closing}/_expected.js (100%) rename test/form/samples/jsx/{preserves-jsx => preserves-jsx-self-closing}/main.js (100%) create mode 100644 test/form/samples/jsx/transpiles-jsx-child/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-child/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-child/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-closing/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-closing/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-closing/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-empty-expression/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-empty-expression/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-expression/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-expression/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-expression/dep1.js create mode 100644 test/form/samples/jsx/transpiles-jsx-expression/dep2.js create mode 100644 test/form/samples/jsx/transpiles-jsx-expression/dep3.js create mode 100644 test/form/samples/jsx/transpiles-jsx-expression/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-fragment/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-fragment/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-fragment/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-self-closing/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-self-closing/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-self-closing/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-text/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-text/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-text/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/main.js diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index e4438ca2615..1fcc7cf82e2 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -5,7 +5,8 @@ import type { InclusionContext } from '../ExecutionContext'; import LocalVariable from '../variables/LocalVariable'; import type Variable from '../variables/Variable'; import type JSXClosingElement from './JSXClosingElement'; -import type JSXExpressionContainer from './JSXExpressionContainer'; +import JSXEmptyExpression from './JSXEmptyExpression'; +import JSXExpressionContainer from './JSXExpressionContainer'; import type JSXFragment from './JSXFragment'; import type JSXOpeningElement from './JSXOpeningElement'; import type JSXText from './JSXText'; @@ -83,7 +84,21 @@ export default class JSXElement extends NodeBase { `/*#__PURE__*/${[this.factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, { contentOnly: true } ); - code.overwrite(this.openingElement.name.end, this.end, `, null)`, { contentOnly: true }); + let insertPostion = this.openingElement.name.end; + // TODO do this in the opening element + code.appendLeft(insertPostion, `, null`); + for (const child of this.children) { + if ( + child instanceof JSXExpressionContainer && + child.expression instanceof JSXEmptyExpression + ) { + code.remove(insertPostion, child.end); + } else { + code.overwrite(insertPostion, child.start, `, `, { contentOnly: true }); + insertPostion = child.end; + } + } + code.overwrite(insertPostion, this.end, `)`, { contentOnly: true }); } } } diff --git a/src/ast/nodes/JSXExpressionContainer.ts b/src/ast/nodes/JSXExpressionContainer.ts index 703aa682214..746de6ede97 100644 --- a/src/ast/nodes/JSXExpressionContainer.ts +++ b/src/ast/nodes/JSXExpressionContainer.ts @@ -1,3 +1,6 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; +import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXEmptyExpression from './JSXEmptyExpression'; import type * as NodeType from './NodeType'; import type { ExpressionNode } from './shared/Node'; @@ -6,4 +9,13 @@ import { NodeBase } from './shared/Node'; export default class JSXExpressionContainer extends NodeBase { type!: NodeType.tJSXExpressionContainer; expression!: ExpressionNode | JSXEmptyExpression; + + render(code: MagicString, options: RenderOptions): void { + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + code.remove(this.start, this.expression.start); + code.remove(this.expression.end, this.end); + } + this.expression.render(code, options); + } } diff --git a/src/utils/options/options.ts b/src/utils/options/options.ts index c6117907b86..53ee5f36329 100644 --- a/src/utils/options/options.ts +++ b/src/utils/options/options.ts @@ -161,7 +161,7 @@ export const jsxPresets: { 'react-jsx': { factory: 'jsx', fragmentFactory: 'Fragment', - importSource: 'react', + importSource: 'react/jsx-runtime', preserve: false } }; diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js index deba7dd3240..ea00c851882 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -1,6 +1,6 @@ module.exports = defineTest({ solo: true, - description: 'preserves JSX output', + description: 'preserves JSX children', options: { external: ['react'], jsx: 'preserve' diff --git a/test/form/samples/jsx/preserves-jsx-closing/_config.js b/test/form/samples/jsx/preserves-jsx-closing/_config.js index deba7dd3240..9aa757698de 100644 --- a/test/form/samples/jsx/preserves-jsx-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-closing/_config.js @@ -1,6 +1,6 @@ module.exports = defineTest({ solo: true, - description: 'preserves JSX output', + description: 'preserves JSX closing element', options: { external: ['react'], jsx: 'preserve' diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js deleted file mode 100644 index 07a102b2a7c..00000000000 --- a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_expected.js +++ /dev/null @@ -1,4 +0,0 @@ -const Foo = () => {}; -const result = {'test'}; - -export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js b/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js deleted file mode 100644 index 22471ece420..00000000000 --- a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/main.js +++ /dev/null @@ -1,2 +0,0 @@ -const Foo = () => {}; -export const result = {'test'}; diff --git a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js b/test/form/samples/jsx/preserves-jsx-expression/_config.js similarity index 70% rename from test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js rename to test/form/samples/jsx/preserves-jsx-expression/_config.js index deba7dd3240..60e522a1646 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-literal-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-expression/_config.js @@ -1,6 +1,6 @@ module.exports = defineTest({ solo: true, - description: 'preserves JSX output', + description: 'preserves JSX expressions', options: { external: ['react'], jsx: 'preserve' diff --git a/test/form/samples/jsx/preserves-jsx-expression/_expected.js b/test/form/samples/jsx/preserves-jsx-expression/_expected.js new file mode 100644 index 00000000000..09dcebdd9d3 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-expression/_expected.js @@ -0,0 +1,13 @@ +const element$2 = 'element 1'; +console.log(element$2); + +const element$1 = 'element 2'; +console.log(element$1); + +const element = 'element 3'; +console.log(element); + +const Foo = () => {}; +const result = {'test' + element$1}; + +export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-expression/dep1.js b/test/form/samples/jsx/preserves-jsx-expression/dep1.js new file mode 100644 index 00000000000..dd37912ccca --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-expression/dep1.js @@ -0,0 +1,2 @@ +export const element = 'element 1'; +console.log(element); diff --git a/test/form/samples/jsx/preserves-jsx-expression/dep2.js b/test/form/samples/jsx/preserves-jsx-expression/dep2.js new file mode 100644 index 00000000000..a9713f489a9 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-expression/dep2.js @@ -0,0 +1,2 @@ +export const element = 'element 2'; +console.log(element); diff --git a/test/form/samples/jsx/preserves-jsx-expression/dep3.js b/test/form/samples/jsx/preserves-jsx-expression/dep3.js new file mode 100644 index 00000000000..de220a40890 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-expression/dep3.js @@ -0,0 +1,2 @@ +export const element = 'element 3'; +console.log(element); diff --git a/test/form/samples/jsx/preserves-jsx-expression/main.js b/test/form/samples/jsx/preserves-jsx-expression/main.js new file mode 100644 index 00000000000..910b3247986 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-expression/main.js @@ -0,0 +1,6 @@ +import "./dep1.js"; +import { element } from "./dep2.js"; +import "./dep3.js"; + +const Foo = () => {}; +export const result = {'test' + element}; diff --git a/test/form/samples/jsx/preserves-jsx/_config.js b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js similarity index 60% rename from test/form/samples/jsx/preserves-jsx/_config.js rename to test/form/samples/jsx/preserves-jsx-self-closing/_config.js index fd757675c75..ecb1f714963 100644 --- a/test/form/samples/jsx/preserves-jsx/_config.js +++ b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js @@ -1,6 +1,6 @@ module.exports = defineTest({ solo: true, - description: 'preserves JSX output', + description: 'preserves self-closing JSX elements', options: { jsx: 'preserve' } diff --git a/test/form/samples/jsx/preserves-jsx/_expected.js b/test/form/samples/jsx/preserves-jsx-self-closing/_expected.js similarity index 100% rename from test/form/samples/jsx/preserves-jsx/_expected.js rename to test/form/samples/jsx/preserves-jsx-self-closing/_expected.js diff --git a/test/form/samples/jsx/preserves-jsx/main.js b/test/form/samples/jsx/preserves-jsx-self-closing/main.js similarity index 100% rename from test/form/samples/jsx/preserves-jsx/main.js rename to test/form/samples/jsx/preserves-jsx-self-closing/main.js diff --git a/test/form/samples/jsx/preserves-jsx-text/_config.js b/test/form/samples/jsx/preserves-jsx-text/_config.js index deba7dd3240..07bcfdc8aea 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_config.js +++ b/test/form/samples/jsx/preserves-jsx-text/_config.js @@ -1,6 +1,6 @@ module.exports = defineTest({ solo: true, - description: 'preserves JSX output', + description: 'preserves JSX text', options: { external: ['react'], jsx: 'preserve' diff --git a/test/form/samples/jsx/preserves-jsx-text/main.js b/test/form/samples/jsx/preserves-jsx-text/main.js index 6af9245a78f..fe06e2e819f 100644 --- a/test/form/samples/jsx/preserves-jsx-text/main.js +++ b/test/form/samples/jsx/preserves-jsx-text/main.js @@ -1,2 +1,2 @@ const Foo = () => {}; -export const result = some-text; +export const result = some-text ; diff --git a/test/form/samples/jsx/transpiles-jsx-child/_config.js b/test/form/samples/jsx/transpiles-jsx-child/_config.js new file mode 100644 index 00000000000..c7ad9f42b8d --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-child/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX children', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-child/_expected.js b/test/form/samples/jsx/transpiles-jsx-child/_expected.js new file mode 100644 index 00000000000..4bd347ce59f --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-child/_expected.js @@ -0,0 +1,6 @@ +import react from 'react'; + +const Foo = () => {}; +const result = /*#__PURE__*/react.createElement(Foo, null, /*#__PURE__*/react.createElement(Foo, null)); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-child/main.js b/test/form/samples/jsx/transpiles-jsx-child/main.js new file mode 100644 index 00000000000..c863c74f668 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-child/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +export const result = ; diff --git a/test/form/samples/jsx/transpiles-jsx-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-closing/_config.js new file mode 100644 index 00000000000..533cbcf1f3f --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-closing/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX closing element', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-closing/_expected.js b/test/form/samples/jsx/transpiles-jsx-closing/_expected.js new file mode 100644 index 00000000000..1a54860615d --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-closing/_expected.js @@ -0,0 +1,6 @@ +import react from 'react'; + +const Foo = () => {}; +const result = /*#__PURE__*/react.createElement(Foo, null); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-closing/main.js b/test/form/samples/jsx/transpiles-jsx-closing/main.js new file mode 100644 index 00000000000..9c2716421ca --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-closing/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +export const result = ; diff --git a/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js new file mode 100644 index 00000000000..3d8b1ae8455 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX output', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-empty-expression/_expected.js b/test/form/samples/jsx/transpiles-jsx-empty-expression/_expected.js new file mode 100644 index 00000000000..1a54860615d --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-empty-expression/_expected.js @@ -0,0 +1,6 @@ +import react from 'react'; + +const Foo = () => {}; +const result = /*#__PURE__*/react.createElement(Foo, null); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-empty-expression/main.js b/test/form/samples/jsx/transpiles-jsx-empty-expression/main.js new file mode 100644 index 00000000000..cb5632fc2f2 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-empty-expression/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +export const result = {}; diff --git a/test/form/samples/jsx/transpiles-jsx-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-expression/_config.js new file mode 100644 index 00000000000..3e4cce8489a --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-expression/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX expressions', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-expression/_expected.js b/test/form/samples/jsx/transpiles-jsx-expression/_expected.js new file mode 100644 index 00000000000..3a792d73525 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-expression/_expected.js @@ -0,0 +1,15 @@ +import react from 'react'; + +const element$2 = 'element 1'; +console.log(element$2); + +const element$1 = 'element 2'; +console.log(element$1); + +const element = 'element 3'; +console.log(element); + +const Foo = () => {}; +const result = /*#__PURE__*/react.createElement(Foo, null, 'test' + element$1); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-expression/dep1.js b/test/form/samples/jsx/transpiles-jsx-expression/dep1.js new file mode 100644 index 00000000000..dd37912ccca --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-expression/dep1.js @@ -0,0 +1,2 @@ +export const element = 'element 1'; +console.log(element); diff --git a/test/form/samples/jsx/transpiles-jsx-expression/dep2.js b/test/form/samples/jsx/transpiles-jsx-expression/dep2.js new file mode 100644 index 00000000000..a9713f489a9 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-expression/dep2.js @@ -0,0 +1,2 @@ +export const element = 'element 2'; +console.log(element); diff --git a/test/form/samples/jsx/transpiles-jsx-expression/dep3.js b/test/form/samples/jsx/transpiles-jsx-expression/dep3.js new file mode 100644 index 00000000000..de220a40890 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-expression/dep3.js @@ -0,0 +1,2 @@ +export const element = 'element 3'; +console.log(element); diff --git a/test/form/samples/jsx/transpiles-jsx-expression/main.js b/test/form/samples/jsx/transpiles-jsx-expression/main.js new file mode 100644 index 00000000000..910b3247986 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-expression/main.js @@ -0,0 +1,6 @@ +import "./dep1.js"; +import { element } from "./dep2.js"; +import "./dep3.js"; + +const Foo = () => {}; +export const result = {'test' + element}; diff --git a/test/form/samples/jsx/transpiles-jsx-fragment/_config.js b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js new file mode 100644 index 00000000000..3d8b1ae8455 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX output', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-fragment/_expected.js b/test/form/samples/jsx/transpiles-jsx-fragment/_expected.js new file mode 100644 index 00000000000..b94656fe42f --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-fragment/_expected.js @@ -0,0 +1,6 @@ +import react from "react"; + +const Foo = () => {}; +const result = /*#__PURE__*/react.createElement(Foo, null, /*#__PURE__*/react.createElement(react.Fragment, null)); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-fragment/main.js b/test/form/samples/jsx/transpiles-jsx-fragment/main.js new file mode 100644 index 00000000000..14a6baf4604 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-fragment/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +export const result = <>; diff --git a/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js new file mode 100644 index 00000000000..aadd9cef2a9 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles self-closing JSX elements', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-self-closing/_expected.js b/test/form/samples/jsx/transpiles-jsx-self-closing/_expected.js new file mode 100644 index 00000000000..1a54860615d --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-self-closing/_expected.js @@ -0,0 +1,6 @@ +import react from 'react'; + +const Foo = () => {}; +const result = /*#__PURE__*/react.createElement(Foo, null); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-self-closing/main.js b/test/form/samples/jsx/transpiles-jsx-self-closing/main.js new file mode 100644 index 00000000000..1e56ff70298 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-self-closing/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +export const result = ; diff --git a/test/form/samples/jsx/transpiles-jsx-text/_config.js b/test/form/samples/jsx/transpiles-jsx-text/_config.js new file mode 100644 index 00000000000..301d244b0ee --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-text/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX text', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-text/_expected.js b/test/form/samples/jsx/transpiles-jsx-text/_expected.js new file mode 100644 index 00000000000..b096d980618 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-text/_expected.js @@ -0,0 +1,6 @@ +import react from "react"; + +const Foo = () => {}; +const result = /*#__PURE__*/react.createElement(Foo, null, 'some-text'); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-text/main.js b/test/form/samples/jsx/transpiles-jsx-text/main.js new file mode 100644 index 00000000000..ee709e17fc4 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-text/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +export const result = some-textfoo ; diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/_config.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/_config.js new file mode 100644 index 00000000000..2fd4e047609 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-with-attributes/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX with string attributes output', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js new file mode 100644 index 00000000000..71474e55170 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js @@ -0,0 +1,10 @@ +import react from "react"; + +const Foo = () => {}; +const result = /*#__PURE__*/react.createElement(Foo, { + bar: true, + baz: "string", + quux: 'expression' +}); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js new file mode 100644 index 00000000000..d5a0cfaab7b --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +export const result = ; diff --git a/test/form/samples/jsx/transpiles-react-jsx/_expected.js b/test/form/samples/jsx/transpiles-react-jsx/_expected.js index 706117213bb..88ebb128476 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_expected.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_expected.js @@ -1,4 +1,4 @@ -import { jsx as jsx$2 } from 'react'; +import { jsx as jsx$2 } from 'react/jsx-runtime'; const Foo$2 = 'wrong Foo 1'; const jsx$1 = 'wrong jsx 1'; From 79da44ef3078c17f6aa7d8ae3ea512f6df33b5c4 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 11 May 2024 06:52:23 +0200 Subject: [PATCH 21/62] Handle JSXText --- src/ast/nodes/JSXText.ts | 12 ++++++++++++ .../form/samples/jsx/preserves-jsx-text/_expected.js | 2 +- test/form/samples/jsx/preserves-jsx-text/main.js | 2 +- .../samples/jsx/transpiles-jsx-text/_expected.js | 4 ++-- test/form/samples/jsx/transpiles-jsx-text/main.js | 2 +- .../form/samples/jsx/transpiles-react-jsx/_config.js | 2 +- test/utils.js | 5 +++++ 7 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/ast/nodes/JSXText.ts b/src/ast/nodes/JSXText.ts index 5045952aa09..40a7fce93cd 100644 --- a/src/ast/nodes/JSXText.ts +++ b/src/ast/nodes/JSXText.ts @@ -1,3 +1,5 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; @@ -5,4 +7,14 @@ export default class JSXText extends NodeBase { type!: NodeType.tJSXText; value!: string; raw!: string; + + render(code: MagicString) { + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + console.log(this.value, this.raw); + code.overwrite(this.start, this.end, JSON.stringify(this.value), { + contentOnly: true + }); + } + } } diff --git a/test/form/samples/jsx/preserves-jsx-text/_expected.js b/test/form/samples/jsx/preserves-jsx-text/_expected.js index 63fade57bb1..6bf468b35e7 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-text/_expected.js @@ -1,4 +1,4 @@ const Foo = () => {}; -const result = some-text; +const result = some&\text; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-text/main.js b/test/form/samples/jsx/preserves-jsx-text/main.js index fe06e2e819f..6e7d20c90f3 100644 --- a/test/form/samples/jsx/preserves-jsx-text/main.js +++ b/test/form/samples/jsx/preserves-jsx-text/main.js @@ -1,2 +1,2 @@ const Foo = () => {}; -export const result = some-text ; +export const result = some&\text; diff --git a/test/form/samples/jsx/transpiles-jsx-text/_expected.js b/test/form/samples/jsx/transpiles-jsx-text/_expected.js index b096d980618..af70022e121 100644 --- a/test/form/samples/jsx/transpiles-jsx-text/_expected.js +++ b/test/form/samples/jsx/transpiles-jsx-text/_expected.js @@ -1,6 +1,6 @@ -import react from "react"; +import react from 'react'; const Foo = () => {}; -const result = /*#__PURE__*/react.createElement(Foo, null, 'some-text'); +const result = /*#__PURE__*/react.createElement(Foo, null, "some&\\text"); export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-text/main.js b/test/form/samples/jsx/transpiles-jsx-text/main.js index ee709e17fc4..6e7d20c90f3 100644 --- a/test/form/samples/jsx/transpiles-jsx-text/main.js +++ b/test/form/samples/jsx/transpiles-jsx-text/main.js @@ -1,2 +1,2 @@ const Foo = () => {}; -export const result = some-textfoo ; +export const result = some&\text; diff --git a/test/form/samples/jsx/transpiles-react-jsx/_config.js b/test/form/samples/jsx/transpiles-react-jsx/_config.js index 3c7f8e3b36a..a144b877eb3 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_config.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_config.js @@ -2,7 +2,7 @@ module.exports = defineTest({ solo: true, description: 'transpiles JSX for react', options: { - external: ['react'], + external: ['react/jsx-runtime'], jsx: 'react-jsx' } }); diff --git a/test/utils.js b/test/utils.js index 3810211bc2e..85b09394fbe 100644 --- a/test/utils.js +++ b/test/utils.js @@ -490,6 +490,11 @@ const replaceStringifyValues = (key, value) => { const { decorators, ...rest } = value; return rest; } + case 'JSXText': { + // raw text is encoded differently in acorn + const { raw, ...nonRawProperties } = value; + return nonRawProperties; + } } return key.startsWith('_') From 4e25b16db6d1b19da8812b99798a087d2582ca46 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 12 May 2024 06:36:55 +0200 Subject: [PATCH 22/62] Support attributes transpilation --- src/ast/nodes/JSXAttribute.ts | 21 +++++ src/ast/nodes/JSXClosingElement.ts | 9 ++ src/ast/nodes/JSXElement.ts | 78 ++--------------- src/ast/nodes/JSXOpeningElement.ts | 87 ++++++++++++++++++- .../_expected.js | 11 ++- .../jsx/preserves-jsx-with-attributes/dep1.js | 2 + .../jsx/preserves-jsx-with-attributes/dep2.js | 2 + .../jsx/preserves-jsx-with-attributes/dep3.js | 2 + .../jsx/preserves-jsx-with-attributes/main.js | 6 +- .../_expected.js | 17 ++-- .../transpiles-jsx-with-attributes/dep1.js | 2 + .../transpiles-jsx-with-attributes/dep2.js | 2 + .../transpiles-jsx-with-attributes/dep3.js | 2 + .../transpiles-jsx-with-attributes/main.js | 6 +- 14 files changed, 168 insertions(+), 79 deletions(-) create mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/dep1.js create mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/dep2.js create mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/dep3.js create mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/dep1.js create mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/dep2.js create mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/dep3.js diff --git a/src/ast/nodes/JSXAttribute.ts b/src/ast/nodes/JSXAttribute.ts index 89ae789ae43..288f416f6ef 100644 --- a/src/ast/nodes/JSXAttribute.ts +++ b/src/ast/nodes/JSXAttribute.ts @@ -1,3 +1,7 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; +import { stringifyObjectKeyIfNeeded } from '../../utils/identifierHelpers'; +import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXElement from './JSXElement'; import type JSXExpressionContainer from './JSXExpressionContainer'; import type JSXFragment from './JSXFragment'; @@ -10,4 +14,21 @@ export default class JSXAttribute extends NodeBase { type!: NodeType.tJSXAttribute; name!: JSXIdentifier /* TODO | JSXNamespacedName */; value!: Literal | JSXExpressionContainer | JSXElement | JSXFragment | null; + + render(code: MagicString, options: RenderOptions): void { + super.render(code, options); + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + const key = this.name.name; + const safeKey = stringifyObjectKeyIfNeeded(key); + if (key !== safeKey) { + code.overwrite(this.name.start, this.name.end, safeKey, { contentOnly: true }); + } + if (this.value) { + code.overwrite(this.name.end, this.value.start, ': ', { contentOnly: true }); + } else { + code.appendLeft(this.name.end, ': true'); + } + } + } } diff --git a/src/ast/nodes/JSXClosingElement.ts b/src/ast/nodes/JSXClosingElement.ts index 792f5c31b07..bc98c9f2465 100644 --- a/src/ast/nodes/JSXClosingElement.ts +++ b/src/ast/nodes/JSXClosingElement.ts @@ -1,3 +1,5 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; import type JSXIdentifier from './JSXIdentifier'; import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; @@ -5,4 +7,11 @@ import { NodeBase } from './shared/Node'; export default class JSXClosingElement extends NodeBase { type!: NodeType.tJSXClosingElement; name!: JSXIdentifier /* TODO | JSXMemberExpression | JSXNamespacedName */; + + render(code: MagicString): void { + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + code.overwrite(this.start, this.end, ')', { contentOnly: true }); + } + } } diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 1fcc7cf82e2..b5c7900f2dd 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -1,9 +1,6 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../rollup/types'; import type { RenderOptions } from '../../utils/renderHelpers'; -import type { InclusionContext } from '../ExecutionContext'; -import LocalVariable from '../variables/LocalVariable'; -import type Variable from '../variables/Variable'; import type JSXClosingElement from './JSXClosingElement'; import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; @@ -11,8 +8,6 @@ import type JSXFragment from './JSXFragment'; import type JSXOpeningElement from './JSXOpeningElement'; import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; -import type { InclusionOptions } from './shared/Expression'; -import type { IncludeChildren } from './shared/Node'; import { NodeBase } from './shared/Node'; export default class JSXElement extends NodeBase { @@ -25,80 +20,25 @@ export default class JSXElement extends NodeBase { | JSXElement | JSXFragment ) /* TODO | JSXSpreadChild */[]; - private factoryVariable: Variable | null = null; - - include( - context: InclusionContext, - includeChildrenRecursively: IncludeChildren, - options?: InclusionOptions - ): void { - if (!this.deoptimized) this.applyDeoptimizations(); - if (!this.included) { - const { factory, importSource, preserve } = this.scope.context.options - .jsx as NormalizedJsxOptions; - if (factory != null) { - const [baseName, nestedName] = factory.split('.'); - if (importSource) { - this.factoryVariable = this.scope.context.getImportedJsxFactoryVariable( - nestedName ? 'default' : baseName, - this.start - ); - if (preserve) { - // This pretends we are accessing an included global variable of the same name - const globalVariable = this.scope.findGlobal(baseName); - globalVariable.include(); - // This excludes this variable from renaming - this.factoryVariable.globalName = baseName; - } - } else { - this.factoryVariable = this.scope.findGlobal(baseName); - } - this.scope.context.includeVariableInModule(this.factoryVariable); - if (this.factoryVariable instanceof LocalVariable) { - this.factoryVariable.consolidateInitializers(); - this.factoryVariable.addUsedPlace(this); - this.scope.context.requestTreeshakingPass(); - } - } - } - super.include(context, includeChildrenRecursively, options); - } - - initialise(): void { - super.initialise(); - this.scope.context.addJsx(); - } render(code: MagicString, options: RenderOptions): void { - super.render(code, options); - const { - snippets: { getPropertyAccess }, - useOriginalName - } = options; - const { factory, preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { - const [, ...nestedName] = factory.split('.'); - code.overwrite( - this.start, - this.openingElement.name.start, - `/*#__PURE__*/${[this.factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, - { contentOnly: true } - ); - let insertPostion = this.openingElement.name.end; - // TODO do this in the opening element - code.appendLeft(insertPostion, `, null`); + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (preserve) { + super.render(code, options); + } else { + this.openingElement.render(code, options); for (const child of this.children) { if ( child instanceof JSXExpressionContainer && child.expression instanceof JSXEmptyExpression ) { - code.remove(insertPostion, child.end); + code.remove(child.start, child.end); } else { - code.overwrite(insertPostion, child.start, `, `, { contentOnly: true }); - insertPostion = child.end; + child.render(code, options); + code.appendRight(child.start, `, `); } } - code.overwrite(insertPostion, this.end, `)`, { contentOnly: true }); + this.closingElement?.render(code); } } } diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index edae9317279..6bbf5c1d885 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -1,11 +1,96 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; +import type { RenderOptions } from '../../utils/renderHelpers'; +import type { InclusionContext } from '../ExecutionContext'; +import LocalVariable from '../variables/LocalVariable'; +import type Variable from '../variables/Variable'; import type JSXAttribute from './JSXAttribute'; import type JSXIdentifier from './JSXIdentifier'; import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; +import type { InclusionOptions } from './shared/Expression'; +import { type IncludeChildren, NodeBase } from './shared/Node'; export default class JSXOpeningElement extends NodeBase { type!: NodeType.tJSXOpeningElement; name!: JSXIdentifier; attributes!: JSXAttribute /* TODO | JSXSpreadAttribute */[]; selfClosing!: boolean; + + private factoryVariable: Variable | null = null; + + include( + context: InclusionContext, + includeChildrenRecursively: IncludeChildren, + options?: InclusionOptions + ): void { + if (!this.deoptimized) this.applyDeoptimizations(); + if (!this.included) { + const { factory, importSource, preserve } = this.scope.context.options + .jsx as NormalizedJsxOptions; + if (factory != null) { + const [baseName, nestedName] = factory.split('.'); + if (importSource) { + this.factoryVariable = this.scope.context.getImportedJsxFactoryVariable( + nestedName ? 'default' : baseName, + this.start + ); + if (preserve) { + // This pretends we are accessing an included global variable of the same name + const globalVariable = this.scope.findGlobal(baseName); + globalVariable.include(); + // This excludes this variable from renaming + this.factoryVariable.globalName = baseName; + } + } else { + this.factoryVariable = this.scope.findGlobal(baseName); + } + this.scope.context.includeVariableInModule(this.factoryVariable); + if (this.factoryVariable instanceof LocalVariable) { + this.factoryVariable.consolidateInitializers(); + this.factoryVariable.addUsedPlace(this); + this.scope.context.requestTreeshakingPass(); + } + } + } + super.include(context, includeChildrenRecursively, options); + } + + initialise(): void { + super.initialise(); + this.scope.context.addJsx(); + } + + render(code: MagicString, options: RenderOptions): void { + super.render(code, options); + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + const { factory, preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + const [, ...nestedName] = factory.split('.'); + code.overwrite( + this.start, + this.name.start, + `/*#__PURE__*/${[this.factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, + { contentOnly: true } + ); + if (this.attributes.length > 0) { + code.overwrite(this.name.end, this.attributes[0].start, ', { ', { contentOnly: true }); + for (let index = 0; index < this.attributes.length - 1; index++) { + code.appendLeft(this.attributes[index].end, ', '); + } + code.overwrite(this.attributes.at(-1)!.end, this.end, ' }', { + contentOnly: true + }); + } else { + code.overwrite(this.name.end, this.end, `, null`, { + contentOnly: true + }); + } + if (this.selfClosing) { + code.appendLeft(this.end, ')'); + } + } + } } diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js b/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js index 90df741f466..f6b3eb90273 100644 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js @@ -1,4 +1,13 @@ +const value$2 = 'value 1'; +console.log(value$2); + +const value$1 = 'value 2'; +console.log(value$1); + +const value = 'value 3'; +console.log(value); + const Foo = () => {}; -const result = ; +const result = ; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/dep1.js b/test/form/samples/jsx/preserves-jsx-with-attributes/dep1.js new file mode 100644 index 00000000000..1aa687cc2da --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/dep1.js @@ -0,0 +1,2 @@ +export const value = 'value 1'; +console.log(value); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/dep2.js b/test/form/samples/jsx/preserves-jsx-with-attributes/dep2.js new file mode 100644 index 00000000000..55685c09285 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/dep2.js @@ -0,0 +1,2 @@ +export const value = 'value 2'; +console.log(value); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/dep3.js b/test/form/samples/jsx/preserves-jsx-with-attributes/dep3.js new file mode 100644 index 00000000000..5a85502eebf --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/dep3.js @@ -0,0 +1,2 @@ +export const value = 'value 3'; +console.log(value); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/main.js b/test/form/samples/jsx/preserves-jsx-with-attributes/main.js index d5a0cfaab7b..d2c0720a11d 100644 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/main.js +++ b/test/form/samples/jsx/preserves-jsx-with-attributes/main.js @@ -1,2 +1,6 @@ +import './dep1.js'; +import { value } from './dep2.js'; +import './dep3.js'; + const Foo = () => {}; -export const result = ; +export const result = ; diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js index 71474e55170..b73e9ca7247 100644 --- a/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js +++ b/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js @@ -1,10 +1,15 @@ -import react from "react"; +import react from 'react'; + +const value$2 = 'value 1'; +console.log(value$2); + +const value$1 = 'value 2'; +console.log(value$1); + +const value = 'value 3'; +console.log(value); const Foo = () => {}; -const result = /*#__PURE__*/react.createElement(Foo, { - bar: true, - baz: "string", - quux: 'expression' -}); +const result = /*#__PURE__*/react.createElement(Foo, { bar: true, baz: "string", "quux-nix": value$1 }); export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/dep1.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/dep1.js new file mode 100644 index 00000000000..1aa687cc2da --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-with-attributes/dep1.js @@ -0,0 +1,2 @@ +export const value = 'value 1'; +console.log(value); diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/dep2.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/dep2.js new file mode 100644 index 00000000000..55685c09285 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-with-attributes/dep2.js @@ -0,0 +1,2 @@ +export const value = 'value 2'; +console.log(value); diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/dep3.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/dep3.js new file mode 100644 index 00000000000..5a85502eebf --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-with-attributes/dep3.js @@ -0,0 +1,2 @@ +export const value = 'value 3'; +console.log(value); diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js index d5a0cfaab7b..d2c0720a11d 100644 --- a/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js +++ b/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js @@ -1,2 +1,6 @@ +import './dep1.js'; +import { value } from './dep2.js'; +import './dep3.js'; + const Foo = () => {}; -export const result = ; +export const result = ; From 58a786b99035549e5b077b644ad9cb04e295c307 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 12 May 2024 06:56:47 +0200 Subject: [PATCH 23/62] Support fragments --- src/ast/nodes/JSXClosingFragment.ts | 9 ++ src/ast/nodes/JSXOpeningFragment.ts | 91 ++++++++++++++++++- src/ast/nodes/JSXText.ts | 1 - .../jsx/transpiles-jsx-fragment/_expected.js | 2 +- 4 files changed, 100 insertions(+), 3 deletions(-) diff --git a/src/ast/nodes/JSXClosingFragment.ts b/src/ast/nodes/JSXClosingFragment.ts index 8b7e3699618..9d42f7c09d0 100644 --- a/src/ast/nodes/JSXClosingFragment.ts +++ b/src/ast/nodes/JSXClosingFragment.ts @@ -1,6 +1,15 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; export default class JSXClosingFragment extends NodeBase { type!: NodeType.tJSXClosingFragment; + + render(code: MagicString): void { + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + code.overwrite(this.start, this.end, ')', { contentOnly: true }); + } + } } diff --git a/src/ast/nodes/JSXOpeningFragment.ts b/src/ast/nodes/JSXOpeningFragment.ts index c92161303c4..cb7a6bef70a 100644 --- a/src/ast/nodes/JSXOpeningFragment.ts +++ b/src/ast/nodes/JSXOpeningFragment.ts @@ -1,8 +1,97 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; +import type { RenderOptions } from '../../utils/renderHelpers'; +import type { InclusionContext } from '../ExecutionContext'; +import LocalVariable from '../variables/LocalVariable'; +import type Variable from '../variables/Variable'; import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; +import type { InclusionOptions } from './shared/Expression'; +import { type IncludeChildren, NodeBase } from './shared/Node'; export default class JSXOpeningFragment extends NodeBase { type!: NodeType.tJSXOpeningElement; attributes!: never[]; selfClosing!: false; + + private factoryVariable: Variable | null = null; + private fragmentVariable: Variable | null = null; + + include( + context: InclusionContext, + includeChildrenRecursively: IncludeChildren, + options?: InclusionOptions + ): void { + if (!this.deoptimized) this.applyDeoptimizations(); + if (!this.included) { + const { factory, fragmentFactory, importSource, preserve } = this.scope.context.options + .jsx as NormalizedJsxOptions; + if (factory != null) { + this.factoryVariable = this.getAndIncludeFactoryVariable(factory, preserve, importSource); + } + if (fragmentFactory != null) { + this.fragmentVariable = this.getAndIncludeFactoryVariable( + fragmentFactory, + preserve, + importSource + ); + } + } + super.include(context, includeChildrenRecursively, options); + } + + initialise(): void { + super.initialise(); + this.scope.context.addJsx(); + } + + render(code: MagicString, options: RenderOptions): void { + super.render(code, options); + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + const { factory, fragmentFactory, preserve } = this.scope.context.options + .jsx as NormalizedJsxOptions; + if (!preserve) { + const [, ...nestedFactory] = factory.split('.'); + const [, ...nestedFragment] = fragmentFactory.split('.'); + code.overwrite( + this.start, + this.end, + `/*#__PURE__*/${[this.factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedFactory].join('.')}(${[this.fragmentVariable!.getName(getPropertyAccess, useOriginalName), ...nestedFragment].join('.')}, null`, + { contentOnly: true } + ); + } + } + + private getAndIncludeFactoryVariable( + factory: string, + preserve: boolean, + importSource: string | null + ): Variable { + const [baseName, nestedName] = factory.split('.'); + let factoryVariable: Variable; + if (importSource) { + factoryVariable = this.scope.context.getImportedJsxFactoryVariable( + nestedName ? 'default' : baseName, + this.start + ); + if (preserve) { + // This pretends we are accessing an included global variable of the same name + const globalVariable = this.scope.findGlobal(baseName); + globalVariable.include(); + // This excludes this variable from renaming + factoryVariable.globalName = baseName; + } + } else { + factoryVariable = this.scope.findGlobal(baseName); + } + this.scope.context.includeVariableInModule(factoryVariable); + if (factoryVariable instanceof LocalVariable) { + factoryVariable.consolidateInitializers(); + factoryVariable.addUsedPlace(this); + this.scope.context.requestTreeshakingPass(); + } + return factoryVariable; + } } diff --git a/src/ast/nodes/JSXText.ts b/src/ast/nodes/JSXText.ts index 40a7fce93cd..fe4962bfbd8 100644 --- a/src/ast/nodes/JSXText.ts +++ b/src/ast/nodes/JSXText.ts @@ -11,7 +11,6 @@ export default class JSXText extends NodeBase { render(code: MagicString) { const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; if (!preserve) { - console.log(this.value, this.raw); code.overwrite(this.start, this.end, JSON.stringify(this.value), { contentOnly: true }); diff --git a/test/form/samples/jsx/transpiles-jsx-fragment/_expected.js b/test/form/samples/jsx/transpiles-jsx-fragment/_expected.js index b94656fe42f..c9a08b770b8 100644 --- a/test/form/samples/jsx/transpiles-jsx-fragment/_expected.js +++ b/test/form/samples/jsx/transpiles-jsx-fragment/_expected.js @@ -1,4 +1,4 @@ -import react from "react"; +import react from 'react'; const Foo = () => {}; const result = /*#__PURE__*/react.createElement(Foo, null, /*#__PURE__*/react.createElement(react.Fragment, null)); From 2bbb5722518b737441b61d8c7d5eca9cd9393f03 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 12 May 2024 07:07:23 +0200 Subject: [PATCH 24/62] Extract shared code from fragments --- src/ast/nodes/JSXClosingElement.ts | 13 +----- src/ast/nodes/JSXClosingFragment.ts | 13 +----- src/ast/nodes/JSXOpeningElement.ts | 52 +-------------------- src/ast/nodes/JSXOpeningFragment.ts | 49 ++------------------ src/ast/nodes/shared/JSXClosingBase.ts | 12 +++++ src/ast/nodes/shared/JSXOpeningBase.ts | 62 ++++++++++++++++++++++++++ 6 files changed, 84 insertions(+), 117 deletions(-) create mode 100644 src/ast/nodes/shared/JSXClosingBase.ts create mode 100644 src/ast/nodes/shared/JSXOpeningBase.ts diff --git a/src/ast/nodes/JSXClosingElement.ts b/src/ast/nodes/JSXClosingElement.ts index bc98c9f2465..1af7441d2ff 100644 --- a/src/ast/nodes/JSXClosingElement.ts +++ b/src/ast/nodes/JSXClosingElement.ts @@ -1,17 +1,8 @@ -import type MagicString from 'magic-string'; -import type { NormalizedJsxOptions } from '../../rollup/types'; import type JSXIdentifier from './JSXIdentifier'; import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; +import JSXClosingBase from './shared/JSXClosingBase'; -export default class JSXClosingElement extends NodeBase { +export default class JSXClosingElement extends JSXClosingBase { type!: NodeType.tJSXClosingElement; name!: JSXIdentifier /* TODO | JSXMemberExpression | JSXNamespacedName */; - - render(code: MagicString): void { - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { - code.overwrite(this.start, this.end, ')', { contentOnly: true }); - } - } } diff --git a/src/ast/nodes/JSXClosingFragment.ts b/src/ast/nodes/JSXClosingFragment.ts index 9d42f7c09d0..a562f09de0b 100644 --- a/src/ast/nodes/JSXClosingFragment.ts +++ b/src/ast/nodes/JSXClosingFragment.ts @@ -1,15 +1,6 @@ -import type MagicString from 'magic-string'; -import type { NormalizedJsxOptions } from '../../rollup/types'; import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; +import JSXClosingBase from './shared/JSXClosingBase'; -export default class JSXClosingFragment extends NodeBase { +export default class JSXClosingFragment extends JSXClosingBase { type!: NodeType.tJSXClosingFragment; - - render(code: MagicString): void { - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { - code.overwrite(this.start, this.end, ')', { contentOnly: true }); - } - } } diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index 6bbf5c1d885..480179e3574 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -1,65 +1,17 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../rollup/types'; import type { RenderOptions } from '../../utils/renderHelpers'; -import type { InclusionContext } from '../ExecutionContext'; -import LocalVariable from '../variables/LocalVariable'; -import type Variable from '../variables/Variable'; import type JSXAttribute from './JSXAttribute'; import type JSXIdentifier from './JSXIdentifier'; import type * as NodeType from './NodeType'; -import type { InclusionOptions } from './shared/Expression'; -import { type IncludeChildren, NodeBase } from './shared/Node'; +import JSXOpeningBase from './shared/JSXOpeningBase'; -export default class JSXOpeningElement extends NodeBase { +export default class JSXOpeningElement extends JSXOpeningBase { type!: NodeType.tJSXOpeningElement; name!: JSXIdentifier; attributes!: JSXAttribute /* TODO | JSXSpreadAttribute */[]; selfClosing!: boolean; - private factoryVariable: Variable | null = null; - - include( - context: InclusionContext, - includeChildrenRecursively: IncludeChildren, - options?: InclusionOptions - ): void { - if (!this.deoptimized) this.applyDeoptimizations(); - if (!this.included) { - const { factory, importSource, preserve } = this.scope.context.options - .jsx as NormalizedJsxOptions; - if (factory != null) { - const [baseName, nestedName] = factory.split('.'); - if (importSource) { - this.factoryVariable = this.scope.context.getImportedJsxFactoryVariable( - nestedName ? 'default' : baseName, - this.start - ); - if (preserve) { - // This pretends we are accessing an included global variable of the same name - const globalVariable = this.scope.findGlobal(baseName); - globalVariable.include(); - // This excludes this variable from renaming - this.factoryVariable.globalName = baseName; - } - } else { - this.factoryVariable = this.scope.findGlobal(baseName); - } - this.scope.context.includeVariableInModule(this.factoryVariable); - if (this.factoryVariable instanceof LocalVariable) { - this.factoryVariable.consolidateInitializers(); - this.factoryVariable.addUsedPlace(this); - this.scope.context.requestTreeshakingPass(); - } - } - } - super.include(context, includeChildrenRecursively, options); - } - - initialise(): void { - super.initialise(); - this.scope.context.addJsx(); - } - render(code: MagicString, options: RenderOptions): void { super.render(code, options); const { diff --git a/src/ast/nodes/JSXOpeningFragment.ts b/src/ast/nodes/JSXOpeningFragment.ts index cb7a6bef70a..b2aa476fb93 100644 --- a/src/ast/nodes/JSXOpeningFragment.ts +++ b/src/ast/nodes/JSXOpeningFragment.ts @@ -2,18 +2,17 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../rollup/types'; import type { RenderOptions } from '../../utils/renderHelpers'; import type { InclusionContext } from '../ExecutionContext'; -import LocalVariable from '../variables/LocalVariable'; import type Variable from '../variables/Variable'; import type * as NodeType from './NodeType'; import type { InclusionOptions } from './shared/Expression'; -import { type IncludeChildren, NodeBase } from './shared/Node'; +import JSXOpeningBase from './shared/JSXOpeningBase'; +import { type IncludeChildren } from './shared/Node'; -export default class JSXOpeningFragment extends NodeBase { +export default class JSXOpeningFragment extends JSXOpeningBase { type!: NodeType.tJSXOpeningElement; attributes!: never[]; selfClosing!: false; - private factoryVariable: Variable | null = null; private fragmentVariable: Variable | null = null; include( @@ -21,13 +20,9 @@ export default class JSXOpeningFragment extends NodeBase { includeChildrenRecursively: IncludeChildren, options?: InclusionOptions ): void { - if (!this.deoptimized) this.applyDeoptimizations(); if (!this.included) { - const { factory, fragmentFactory, importSource, preserve } = this.scope.context.options + const { fragmentFactory, importSource, preserve } = this.scope.context.options .jsx as NormalizedJsxOptions; - if (factory != null) { - this.factoryVariable = this.getAndIncludeFactoryVariable(factory, preserve, importSource); - } if (fragmentFactory != null) { this.fragmentVariable = this.getAndIncludeFactoryVariable( fragmentFactory, @@ -39,11 +34,6 @@ export default class JSXOpeningFragment extends NodeBase { super.include(context, includeChildrenRecursively, options); } - initialise(): void { - super.initialise(); - this.scope.context.addJsx(); - } - render(code: MagicString, options: RenderOptions): void { super.render(code, options); const { @@ -63,35 +53,4 @@ export default class JSXOpeningFragment extends NodeBase { ); } } - - private getAndIncludeFactoryVariable( - factory: string, - preserve: boolean, - importSource: string | null - ): Variable { - const [baseName, nestedName] = factory.split('.'); - let factoryVariable: Variable; - if (importSource) { - factoryVariable = this.scope.context.getImportedJsxFactoryVariable( - nestedName ? 'default' : baseName, - this.start - ); - if (preserve) { - // This pretends we are accessing an included global variable of the same name - const globalVariable = this.scope.findGlobal(baseName); - globalVariable.include(); - // This excludes this variable from renaming - factoryVariable.globalName = baseName; - } - } else { - factoryVariable = this.scope.findGlobal(baseName); - } - this.scope.context.includeVariableInModule(factoryVariable); - if (factoryVariable instanceof LocalVariable) { - factoryVariable.consolidateInitializers(); - factoryVariable.addUsedPlace(this); - this.scope.context.requestTreeshakingPass(); - } - return factoryVariable; - } } diff --git a/src/ast/nodes/shared/JSXClosingBase.ts b/src/ast/nodes/shared/JSXClosingBase.ts new file mode 100644 index 00000000000..def0e84a429 --- /dev/null +++ b/src/ast/nodes/shared/JSXClosingBase.ts @@ -0,0 +1,12 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../../rollup/types'; +import { NodeBase } from './Node'; + +export default class JSXClosingBase extends NodeBase { + render(code: MagicString): void { + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + code.overwrite(this.start, this.end, ')', { contentOnly: true }); + } + } +} diff --git a/src/ast/nodes/shared/JSXOpeningBase.ts b/src/ast/nodes/shared/JSXOpeningBase.ts new file mode 100644 index 00000000000..b15d2b3a95a --- /dev/null +++ b/src/ast/nodes/shared/JSXOpeningBase.ts @@ -0,0 +1,62 @@ +import type { NormalizedJsxOptions } from '../../../rollup/types'; +import type { InclusionContext } from '../../ExecutionContext'; +import LocalVariable from '../../variables/LocalVariable'; +import type Variable from '../../variables/Variable'; +import type { InclusionOptions } from './Expression'; +import { type IncludeChildren, NodeBase } from './Node'; + +export default class JSXOpeningBase extends NodeBase { + protected factoryVariable: Variable | null = null; + + include( + context: InclusionContext, + includeChildrenRecursively: IncludeChildren, + options?: InclusionOptions + ): void { + if (!this.deoptimized) this.applyDeoptimizations(); + if (!this.included) { + const { factory, importSource, preserve } = this.scope.context.options + .jsx as NormalizedJsxOptions; + if (factory != null) { + this.factoryVariable = this.getAndIncludeFactoryVariable(factory, preserve, importSource); + } + } + super.include(context, includeChildrenRecursively, options); + } + + initialise(): void { + super.initialise(); + this.scope.context.addJsx(); + } + + protected getAndIncludeFactoryVariable( + factory: string, + preserve: boolean, + importSource: string | null + ): Variable { + const [baseName, nestedName] = factory.split('.'); + let factoryVariable: Variable; + if (importSource) { + factoryVariable = this.scope.context.getImportedJsxFactoryVariable( + nestedName ? 'default' : baseName, + this.start + ); + if (preserve) { + // This pretends we are accessing an included global variable of the same name + const globalVariable = this.scope.findGlobal(baseName); + globalVariable.include(); + // This excludes this variable from renaming + factoryVariable.globalName = baseName; + } + } else { + factoryVariable = this.scope.findGlobal(baseName); + } + this.scope.context.includeVariableInModule(factoryVariable); + if (factoryVariable instanceof LocalVariable) { + factoryVariable.consolidateInitializers(); + factoryVariable.addUsedPlace(this); + this.scope.context.requestTreeshakingPass(); + } + return factoryVariable; + } +} From 9680b65b842b823be31e2c597fdc05174f994419 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 12 May 2024 19:54:32 +0200 Subject: [PATCH 25/62] Support JSXText in all possible positions --- rust/parse_ast/src/convert_ast/converter.rs | 7 +++-- src/ast/nodes/JSXFragment.ts | 27 ++++++++++++++++++- .../jsx/preserves-jsx-text/_expected.js | 5 ++-- .../samples/jsx/preserves-jsx-text/main.js | 3 ++- .../jsx/transpiles-jsx-text/_expected.js | 5 ++-- .../samples/jsx/transpiles-jsx-text/main.js | 3 ++- 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 86620358089..02ca99bd19e 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -862,10 +862,9 @@ impl<'a> AstConverter<'a> { self.convert_item_list( &jsx_fragment.children, end_position + JSX_FRAGMENT_CHILDREN_OFFSET, - |_ast_converter, _jsx_fragment_child| { - unimplemented!("Convert JSXFragmentChild"); - // ast_converter.convert_jsx_fragment_child(jsx_fragment_child); - // true + |ast_converter, jsx_element_child| { + ast_converter.convert_jsx_element_child(jsx_element_child); + true }, ); // closingFragment diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index f7531529b6a..5bc5849aba9 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -1,6 +1,10 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; +import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXClosingFragment from './JSXClosingFragment'; import type JSXElement from './JSXElement'; -import type JSXExpressionContainer from './JSXExpressionContainer'; +import JSXEmptyExpression from './JSXEmptyExpression'; +import JSXExpressionContainer from './JSXExpressionContainer'; import type JSXFragment from './JSXFragment'; import type JSXOpeningFragment from './JSXOpeningFragment'; import type JSXText from './JSXText'; @@ -17,4 +21,25 @@ export default class JsxElement extends NodeBase { | JSXFragment )[]; closingFragment!: JSXClosingFragment; + + render(code: MagicString, options: RenderOptions): void { + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (preserve) { + super.render(code, options); + } else { + this.openingFragment.render(code, options); + for (const child of this.children) { + if ( + child instanceof JSXExpressionContainer && + child.expression instanceof JSXEmptyExpression + ) { + code.remove(child.start, child.end); + } else { + child.render(code, options); + code.appendRight(child.start, `, `); + } + } + this.closingFragment?.render(code); + } + } } diff --git a/test/form/samples/jsx/preserves-jsx-text/_expected.js b/test/form/samples/jsx/preserves-jsx-text/_expected.js index 6bf468b35e7..3e62794eb38 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-text/_expected.js @@ -1,4 +1,5 @@ const Foo = () => {}; -const result = some&\text; +const element = some&\text; +const fragment = <>other&\text; -export { result }; +export { element, fragment }; diff --git a/test/form/samples/jsx/preserves-jsx-text/main.js b/test/form/samples/jsx/preserves-jsx-text/main.js index 6e7d20c90f3..e8e2d995543 100644 --- a/test/form/samples/jsx/preserves-jsx-text/main.js +++ b/test/form/samples/jsx/preserves-jsx-text/main.js @@ -1,2 +1,3 @@ const Foo = () => {}; -export const result = some&\text; +export const element = some&\text; +export const fragment = <>other&\text; diff --git a/test/form/samples/jsx/transpiles-jsx-text/_expected.js b/test/form/samples/jsx/transpiles-jsx-text/_expected.js index af70022e121..52f72067dad 100644 --- a/test/form/samples/jsx/transpiles-jsx-text/_expected.js +++ b/test/form/samples/jsx/transpiles-jsx-text/_expected.js @@ -1,6 +1,7 @@ import react from 'react'; const Foo = () => {}; -const result = /*#__PURE__*/react.createElement(Foo, null, "some&\\text"); +const element = /*#__PURE__*/react.createElement(Foo, null, "some&\\text"); +const fragment = /*#__PURE__*/react.createElement(react.Fragment, null, "other&\\text"); -export { result }; +export { element, fragment }; diff --git a/test/form/samples/jsx/transpiles-jsx-text/main.js b/test/form/samples/jsx/transpiles-jsx-text/main.js index 6e7d20c90f3..e8e2d995543 100644 --- a/test/form/samples/jsx/transpiles-jsx-text/main.js +++ b/test/form/samples/jsx/transpiles-jsx-text/main.js @@ -1,2 +1,3 @@ const Foo = () => {}; -export const result = some&\text; +export const element = some&\text; +export const fragment = <>other&\text; From 4fad480644779de821f4e8f8de38dedefceece97 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 13 May 2024 06:53:48 +0200 Subject: [PATCH 26/62] Support all possible JSX attribute types --- rust/parse_ast/src/convert_ast/converter.rs | 43 ++++++++++++----- .../convert_ast/converter/ast_constants.rs | 39 ++++++++------- .../src/convert_ast/converter/ast_macros.rs | 48 +++++++++---------- scripts/ast-types.js | 8 ++++ src/ast/bufferParsers.ts | 8 ++++ src/ast/childNodeKeys.ts | 1 + src/ast/nodes/JSXAttribute.ts | 17 ++++--- src/ast/nodes/JSXIdentifier.ts | 3 +- src/ast/nodes/JSXNamespacedName.ts | 9 ++++ src/ast/nodes/JSXOpeningElement.ts | 2 +- src/ast/nodes/NodeType.ts | 2 + src/ast/nodes/index.ts | 2 + src/utils/bufferToAst.ts | 10 ++++ .../_config.js | 0 .../jsx/preserves-jsx-attributes/_expected.js | 15 ++++++ .../jsx/preserves-jsx-attributes/dep1.js | 3 ++ .../jsx/preserves-jsx-attributes/dep2.js | 3 ++ .../jsx/preserves-jsx-attributes/dep3.js | 3 ++ .../jsx/preserves-jsx-attributes/main.js | 5 ++ .../_expected.js | 13 ----- .../jsx/preserves-jsx-with-attributes/dep1.js | 2 - .../jsx/preserves-jsx-with-attributes/dep2.js | 2 - .../jsx/preserves-jsx-with-attributes/dep3.js | 2 - .../jsx/preserves-jsx-with-attributes/main.js | 6 --- .../_config.js | 0 .../transpiles-jsx-attributes/_expected.js | 17 +++++++ .../jsx/transpiles-jsx-attributes/dep1.js | 3 ++ .../jsx/transpiles-jsx-attributes/dep2.js | 3 ++ .../jsx/transpiles-jsx-attributes/dep3.js | 3 ++ .../jsx/transpiles-jsx-attributes/main.js | 5 ++ .../_expected.js | 15 ------ .../transpiles-jsx-with-attributes/dep1.js | 2 - .../transpiles-jsx-with-attributes/dep2.js | 2 - .../transpiles-jsx-with-attributes/dep3.js | 2 - .../transpiles-jsx-with-attributes/main.js | 6 --- 35 files changed, 191 insertions(+), 113 deletions(-) create mode 100644 src/ast/nodes/JSXNamespacedName.ts rename test/form/samples/jsx/{preserves-jsx-with-attributes => preserves-jsx-attributes}/_config.js (100%) create mode 100644 test/form/samples/jsx/preserves-jsx-attributes/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-attributes/dep1.js create mode 100644 test/form/samples/jsx/preserves-jsx-attributes/dep2.js create mode 100644 test/form/samples/jsx/preserves-jsx-attributes/dep3.js create mode 100644 test/form/samples/jsx/preserves-jsx-attributes/main.js delete mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js delete mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/dep1.js delete mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/dep2.js delete mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/dep3.js delete mode 100644 test/form/samples/jsx/preserves-jsx-with-attributes/main.js rename test/form/samples/jsx/{transpiles-jsx-with-attributes => transpiles-jsx-attributes}/_config.js (100%) create mode 100644 test/form/samples/jsx/transpiles-jsx-attributes/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-attributes/dep1.js create mode 100644 test/form/samples/jsx/transpiles-jsx-attributes/dep2.js create mode 100644 test/form/samples/jsx/transpiles-jsx-attributes/dep3.js create mode 100644 test/form/samples/jsx/transpiles-jsx-attributes/main.js delete mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js delete mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/dep1.js delete mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/dep2.js delete mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/dep3.js delete mode 100644 test/form/samples/jsx/transpiles-jsx-with-attributes/main.js diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 02ca99bd19e..aaef51332b4 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -3,9 +3,9 @@ use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, JSXClosingElement, JSXClosingFragment, JSXElement, JSXElementChild, JSXElementName, JSXEmptyExpr, - JSXExpr, JSXExprContainer, JSXFragment, JSXOpeningElement, JSXOpeningFragment, JSXText, Lit, - ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, - Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, + JSXExpr, JSXExprContainer, JSXFragment, JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, + JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, + ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; @@ -20,14 +20,15 @@ use crate::convert_ast::converter::ast_constants::{ JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET, JSX_EXPRESSION_CONTAINER_RESERVED_BYTES, JSX_FRAGMENT_CHILDREN_OFFSET, JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET, JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET, JSX_FRAGMENT_RESERVED_BYTES, JSX_IDENTIFIER_NAME_OFFSET, - JSX_IDENTIFIER_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, - JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, - JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_TEXT_RAW_OFFSET, JSX_TEXT_RESERVED_BYTES, - JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, + JSX_IDENTIFIER_RESERVED_BYTES, JSX_NAMESPACED_NAME_NAME_OFFSET, + JSX_NAMESPACED_NAME_NAMESPACE_OFFSET, JSX_NAMESPACED_NAME_RESERVED_BYTES, + JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, + JSX_OPENING_ELEMENT_RESERVED_BYTES, JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_TEXT_RAW_OFFSET, + JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_CLOSING_ELEMENT, TYPE_JSX_CLOSING_FRAGMENT, TYPE_JSX_ELEMENT, TYPE_JSX_EMPTY_EXPRESSION, - TYPE_JSX_EXPRESSION_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, TYPE_JSX_OPENING_ELEMENT, - TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_TEXT, + TYPE_JSX_EXPRESSION_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, TYPE_JSX_NAMESPACED_NAME, + TYPE_JSX_OPENING_ELEMENT, TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_TEXT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -438,8 +439,8 @@ impl<'a> AstConverter<'a> { JSXAttrName::Ident(identifier) => { self.store_jsx_identifier(&identifier.span, &identifier.sym); } - JSXAttrName::JSXNamespacedName(_jsx_namespaced_name) => { - unimplemented!("JSXElementName::JSXNamespacedName") + JSXAttrName::JSXNamespacedName(jsx_namespaced_name) => { + self.convert_jsx_namespaced_name(jsx_namespaced_name); } } } @@ -887,6 +888,26 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, span); } + fn convert_jsx_namespaced_name(&mut self, jsx_namespaced_name: &JSXNamespacedName) { + let end_position = self.add_type_and_start( + &TYPE_JSX_NAMESPACED_NAME, + &jsx_namespaced_name.ns.span, + JSX_NAMESPACED_NAME_RESERVED_BYTES, + false, + ); + // namespace + self.update_reference_position(end_position + JSX_NAMESPACED_NAME_NAMESPACE_OFFSET); + self.store_jsx_identifier(&jsx_namespaced_name.ns.span, &jsx_namespaced_name.ns.sym); + // name + self.update_reference_position(end_position + JSX_NAMESPACED_NAME_NAME_OFFSET); + self.store_jsx_identifier( + &jsx_namespaced_name.name.span, + &jsx_namespaced_name.name.sym, + ); + // end + self.add_end(end_position, &jsx_namespaced_name.name.span); + } + fn convert_jsx_opening_element(&mut self, jsx_opening_element: &JSXOpeningElement) { let end_position = self.add_type_and_start( &TYPE_JSX_OPENING_ELEMENT, diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index 03fb9dcd9c6..cab53fd03c5 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -32,23 +32,24 @@ pub const TYPE_JSX_EMPTY_EXPRESSION: [u8; 4] = 46u32.to_ne_bytes(); pub const TYPE_JSX_EXPRESSION_CONTAINER: [u8; 4] = 47u32.to_ne_bytes(); pub const TYPE_JSX_FRAGMENT: [u8; 4] = 48u32.to_ne_bytes(); pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 49u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 50u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 51u32.to_ne_bytes(); -pub const TYPE_JSX_TEXT: [u8; 4] = 52u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 60u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 61u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 62u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 63u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 64u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 68u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 69u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 70u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 71u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 74u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 81u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 84u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 87u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 88u32.to_ne_bytes(); +pub const TYPE_JSX_NAMESPACED_NAME: [u8; 4] = 50u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 51u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 52u32.to_ne_bytes(); +pub const TYPE_JSX_TEXT: [u8; 4] = 53u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 61u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 62u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 63u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 65u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 69u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 70u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 71u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 72u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 75u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 82u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 85u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 88u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 89u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -163,6 +164,10 @@ pub const JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET: usize = 12; pub const JSX_IDENTIFIER_RESERVED_BYTES: usize = 8; pub const JSX_IDENTIFIER_NAME_OFFSET: usize = 4; +pub const JSX_NAMESPACED_NAME_RESERVED_BYTES: usize = 12; +pub const JSX_NAMESPACED_NAME_NAMESPACE_OFFSET: usize = 4; +pub const JSX_NAMESPACED_NAME_NAME_OFFSET: usize = 8; + pub const JSX_OPENING_ELEMENT_RESERVED_BYTES: usize = 16; pub const JSX_OPENING_ELEMENT_NAME_OFFSET: usize = 8; pub const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index afb3ba95795..64b555fcf1b 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -319,7 +319,7 @@ macro_rules! store_import_specifier { macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&53u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&54u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&54u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &55u32.to_ne_bytes(), + &56u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&65u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&72u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&80u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &80u32.to_ne_bytes(), + &81u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&82u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&83u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&83u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&84u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&85u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&86u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &86u32.to_ne_bytes(), + &87u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&89u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&90u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &90u32.to_ne_bytes(), + &91u32.to_ne_bytes(), &$span, 12, false, diff --git a/scripts/ast-types.js b/scripts/ast-types.js index ed5ab4f976b..bbac2d5be41 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -439,6 +439,14 @@ export const AST_NODES = { fields: [['name', 'String']], useMacro: false }, + JSXNamespacedName: { + estreeType: 'any', + fields: [ + ['namespace', 'Node'], + ['name', 'Node'] + ], + useMacro: false + }, JSXOpeningElement: { estreeType: 'any', fields: [ diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index f411a62e8dc..53c7f54cad4 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -56,6 +56,7 @@ import JSXEmptyExpression from './nodes/JSXEmptyExpression'; import JSXExpressionContainer from './nodes/JSXExpressionContainer'; import JSXFragment from './nodes/JSXFragment'; import JSXIdentifier from './nodes/JSXIdentifier'; +import JSXNamespacedName from './nodes/JSXNamespacedName'; import JSXOpeningElement from './nodes/JSXOpeningElement'; import JSXOpeningFragment from './nodes/JSXOpeningFragment'; import JSXText from './nodes/JSXText'; @@ -160,6 +161,7 @@ const nodeTypeStrings = [ 'JSXExpressionContainer', 'JSXFragment', 'JSXIdentifier', + 'JSXNamespacedName', 'JSXOpeningElement', 'JSXOpeningFragment', 'JSXText', @@ -254,6 +256,7 @@ const nodeConstructors: (typeof NodeBase)[] = [ JSXExpressionContainer, JSXFragment, JSXIdentifier, + JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, JSXText, @@ -631,6 +634,11 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ function jsxIdentifier(node: JSXIdentifier, position, buffer) { node.name = buffer.convertString(buffer[position]); }, + function jsxNamespacedName(node: JSXNamespacedName, position, buffer) { + const { scope } = node; + node.namespace = convertNode(node, scope, buffer[position], buffer); + node.name = convertNode(node, scope, buffer[position + 1], buffer); + }, function jsxOpeningElement(node: JSXOpeningElement, position, buffer) { const { scope } = node; const flags = buffer[position]; diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index 01ee687f231..9ae1a126001 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -49,6 +49,7 @@ export const childNodeKeys: Record = { JSXExpressionContainer: ['expression'], JSXFragment: ['openingFragment', 'children', 'closingFragment'], JSXIdentifier: [], + JSXNamespacedName: ['namespace', 'name'], JSXOpeningElement: ['name', 'attributes'], JSXOpeningFragment: [], JSXText: [], diff --git a/src/ast/nodes/JSXAttribute.ts b/src/ast/nodes/JSXAttribute.ts index 288f416f6ef..0f3134ac910 100644 --- a/src/ast/nodes/JSXAttribute.ts +++ b/src/ast/nodes/JSXAttribute.ts @@ -5,29 +5,32 @@ import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXElement from './JSXElement'; import type JSXExpressionContainer from './JSXExpressionContainer'; import type JSXFragment from './JSXFragment'; -import type JSXIdentifier from './JSXIdentifier'; +import JSXIdentifier from './JSXIdentifier'; +import type JSXNamespacedName from './JSXNamespacedName'; import type Literal from './Literal'; import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; export default class JSXAttribute extends NodeBase { type!: NodeType.tJSXAttribute; - name!: JSXIdentifier /* TODO | JSXNamespacedName */; + name!: JSXIdentifier | JSXNamespacedName; value!: Literal | JSXExpressionContainer | JSXElement | JSXFragment | null; render(code: MagicString, options: RenderOptions): void { super.render(code, options); const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; if (!preserve) { - const key = this.name.name; + const { name, value } = this; + const key = + name instanceof JSXIdentifier ? name.name : `${name.namespace.name}:${name.name.name}`; const safeKey = stringifyObjectKeyIfNeeded(key); if (key !== safeKey) { - code.overwrite(this.name.start, this.name.end, safeKey, { contentOnly: true }); + code.overwrite(name.start, name.end, safeKey, { contentOnly: true }); } - if (this.value) { - code.overwrite(this.name.end, this.value.start, ': ', { contentOnly: true }); + if (value) { + code.overwrite(name.end, value.start, ': ', { contentOnly: true }); } else { - code.appendLeft(this.name.end, ': true'); + code.appendLeft(name.end, ': true'); } } } diff --git a/src/ast/nodes/JSXIdentifier.ts b/src/ast/nodes/JSXIdentifier.ts index 8cc701e132d..7d6efb0ef38 100644 --- a/src/ast/nodes/JSXIdentifier.ts +++ b/src/ast/nodes/JSXIdentifier.ts @@ -37,7 +37,8 @@ export default class JSXIdentifier extends IdentifierBase { case 'JSXClosingElement': { return (this.parent as JSXOpeningElement).name === this; } - case 'JSXAttribute': { + case 'JSXAttribute': + case 'JSXNamespacedName': { return false; } default: { diff --git a/src/ast/nodes/JSXNamespacedName.ts b/src/ast/nodes/JSXNamespacedName.ts new file mode 100644 index 00000000000..5172b2a47a0 --- /dev/null +++ b/src/ast/nodes/JSXNamespacedName.ts @@ -0,0 +1,9 @@ +import type JSXIdentifier from './JSXIdentifier'; +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JSXNamespacedName extends NodeBase { + type!: NodeType.tJSXNamespacedName; + name!: JSXIdentifier; + namespace!: JSXIdentifier; +} diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index 480179e3574..8108c2ea987 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -8,7 +8,7 @@ import JSXOpeningBase from './shared/JSXOpeningBase'; export default class JSXOpeningElement extends JSXOpeningBase { type!: NodeType.tJSXOpeningElement; - name!: JSXIdentifier; + name!: JSXIdentifier; /* TODO | JSXMemberExpression | JSXNamespacedName; */ attributes!: JSXAttribute /* TODO | JSXSpreadAttribute */[]; selfClosing!: boolean; diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index 38f6ba423a2..a17e8946ba0 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -48,6 +48,7 @@ export type tJSXEmptyExpression = 'JSXEmptyExpression'; export type tJSXExpressionContainer = 'JSXExpressionContainer'; export type tJSXFragment = 'JSXFragment'; export type tJSXIdentifier = 'JSXIdentifier'; +export type tJSXNamespacedName = 'JSXNamespacedName'; export type tJSXOpeningElement = 'JSXOpeningElement'; export type tJSXOpeningFragment = 'JSXOpeningFragment'; export type tJSXText = 'JSXText'; @@ -134,6 +135,7 @@ export const JSXEmptyExpression: tJSXEmptyExpression = 'JSXEmptyExpression'; export const JSXExpressionContainer: tJSXExpressionContainer = 'JSXExpressionContainer'; export const JSXFragment: tJSXFragment = 'JSXFragment'; export const JSXIdentifier: tJSXIdentifier = 'JSXIdentifier'; +export const JSXNamespacedName: tJSXNamespacedName = 'JSXNamespacedName'; export const JSXOpeningElement: tJSXOpeningElement = 'JSXOpeningElement'; export const JSXOpeningFragment: tJSXOpeningFragment = 'JSXOpeningFragment'; export const JSXText: tJSXText = 'JSXText'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index a203d713e01..2981e7e839b 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -48,6 +48,7 @@ import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; import JSXFragment from './JSXFragment'; import JSXIdentifier from './JSXIdentifier'; +import JSXNamespacedName from './JSXNamespacedName'; import JSXOpeningElement from './JSXOpeningElement'; import JSXOpeningFragment from './JSXOpeningFragment'; import JSXText from './JSXText'; @@ -137,6 +138,7 @@ export const nodeConstructors: Record = { JSXExpressionContainer, JSXFragment, JSXIdentifier, + JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, JSXText, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index 0a8ec0241f0..fea7363bd7a 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -520,6 +520,15 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ name: buffer.convertString(buffer[position + 2]) }; }, + function jsxNamespacedName(position, buffer): JSXNamespacedNameNode { + return { + type: 'JSXNamespacedName', + start: buffer[position], + end: buffer[position + 1], + namespace: convertNode(buffer[position + 2], buffer), + name: convertNode(buffer[position + 3], buffer) + }; + }, function jsxOpeningElement(position, buffer): JSXOpeningElementNode { const flags = buffer[position + 2]; return { @@ -1002,6 +1011,7 @@ export type JSXEmptyExpressionNode = RollupAstNode; export type JSXExpressionContainerNode = RollupAstNode; export type JSXFragmentNode = RollupAstNode; export type JSXIdentifierNode = RollupAstNode; +export type JSXNamespacedNameNode = RollupAstNode; export type JSXOpeningElementNode = RollupAstNode; export type JSXOpeningFragmentNode = RollupAstNode; export type JSXTextNode = RollupAstNode; diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/_config.js b/test/form/samples/jsx/preserves-jsx-attributes/_config.js similarity index 100% rename from test/form/samples/jsx/preserves-jsx-with-attributes/_config.js rename to test/form/samples/jsx/preserves-jsx-attributes/_config.js diff --git a/test/form/samples/jsx/preserves-jsx-attributes/_expected.js b/test/form/samples/jsx/preserves-jsx-attributes/_expected.js new file mode 100644 index 00000000000..490479abe86 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-attributes/_expected.js @@ -0,0 +1,15 @@ +const Foo$2 = () => {}; +const value$2 = 'value 1'; +console.log(Foo$2, value$2); + +const Foo$1 = () => {}; +const value$1 = 'value 2'; +console.log(Foo$1, value$1); + +const Foo = () => {}; +const value = 'value 3'; +console.log(Foo, value); + +const result = fragment=<> />; + +export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-attributes/dep1.js b/test/form/samples/jsx/preserves-jsx-attributes/dep1.js new file mode 100644 index 00000000000..7e4f005d564 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-attributes/dep1.js @@ -0,0 +1,3 @@ +export const Foo = () => {}; +export const value = 'value 1'; +console.log(Foo, value); diff --git a/test/form/samples/jsx/preserves-jsx-attributes/dep2.js b/test/form/samples/jsx/preserves-jsx-attributes/dep2.js new file mode 100644 index 00000000000..697b1397701 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-attributes/dep2.js @@ -0,0 +1,3 @@ +export const Foo = () => {}; +export const value = 'value 2'; +console.log(Foo, value); diff --git a/test/form/samples/jsx/preserves-jsx-attributes/dep3.js b/test/form/samples/jsx/preserves-jsx-attributes/dep3.js new file mode 100644 index 00000000000..d80368ea8cf --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-attributes/dep3.js @@ -0,0 +1,3 @@ +export const Foo = () => {}; +export const value = 'value 3'; +console.log(Foo, value); diff --git a/test/form/samples/jsx/preserves-jsx-attributes/main.js b/test/form/samples/jsx/preserves-jsx-attributes/main.js new file mode 100644 index 00000000000..3748b4076f4 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-attributes/main.js @@ -0,0 +1,5 @@ +import './dep1.js'; +import { Foo, value } from './dep2.js'; +import './dep3.js'; + +export const result = fragment=<> />; diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js b/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js deleted file mode 100644 index f6b3eb90273..00000000000 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/_expected.js +++ /dev/null @@ -1,13 +0,0 @@ -const value$2 = 'value 1'; -console.log(value$2); - -const value$1 = 'value 2'; -console.log(value$1); - -const value = 'value 3'; -console.log(value); - -const Foo = () => {}; -const result = ; - -export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/dep1.js b/test/form/samples/jsx/preserves-jsx-with-attributes/dep1.js deleted file mode 100644 index 1aa687cc2da..00000000000 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/dep1.js +++ /dev/null @@ -1,2 +0,0 @@ -export const value = 'value 1'; -console.log(value); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/dep2.js b/test/form/samples/jsx/preserves-jsx-with-attributes/dep2.js deleted file mode 100644 index 55685c09285..00000000000 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/dep2.js +++ /dev/null @@ -1,2 +0,0 @@ -export const value = 'value 2'; -console.log(value); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/dep3.js b/test/form/samples/jsx/preserves-jsx-with-attributes/dep3.js deleted file mode 100644 index 5a85502eebf..00000000000 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/dep3.js +++ /dev/null @@ -1,2 +0,0 @@ -export const value = 'value 3'; -console.log(value); diff --git a/test/form/samples/jsx/preserves-jsx-with-attributes/main.js b/test/form/samples/jsx/preserves-jsx-with-attributes/main.js deleted file mode 100644 index d2c0720a11d..00000000000 --- a/test/form/samples/jsx/preserves-jsx-with-attributes/main.js +++ /dev/null @@ -1,6 +0,0 @@ -import './dep1.js'; -import { value } from './dep2.js'; -import './dep3.js'; - -const Foo = () => {}; -export const result = ; diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/_config.js b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js similarity index 100% rename from test/form/samples/jsx/transpiles-jsx-with-attributes/_config.js rename to test/form/samples/jsx/transpiles-jsx-attributes/_config.js diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js b/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js new file mode 100644 index 00000000000..b01053782ee --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js @@ -0,0 +1,17 @@ +import react from 'react'; + +const Foo$2 = () => {}; +const value$2 = 'value 1'; +console.log(Foo$2, value$2); + +const Foo$1 = () => {}; +const value$1 = 'value 2'; +console.log(Foo$1, value$1); + +const Foo = () => {}; +const value = 'value 3'; +console.log(Foo, value); + +const result = /*#__PURE__*/react.createElement(Foo$1, { bar: true, "baz:foo": "string", "quux-nix": value$1, element: /*#__PURE__*/react.createElement(Foo$1, null), fragment: /*#__PURE__*/react.createElement(react.Fragment, null) }); + +export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/dep1.js b/test/form/samples/jsx/transpiles-jsx-attributes/dep1.js new file mode 100644 index 00000000000..7e4f005d564 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-attributes/dep1.js @@ -0,0 +1,3 @@ +export const Foo = () => {}; +export const value = 'value 1'; +console.log(Foo, value); diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/dep2.js b/test/form/samples/jsx/transpiles-jsx-attributes/dep2.js new file mode 100644 index 00000000000..697b1397701 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-attributes/dep2.js @@ -0,0 +1,3 @@ +export const Foo = () => {}; +export const value = 'value 2'; +console.log(Foo, value); diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/dep3.js b/test/form/samples/jsx/transpiles-jsx-attributes/dep3.js new file mode 100644 index 00000000000..d80368ea8cf --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-attributes/dep3.js @@ -0,0 +1,3 @@ +export const Foo = () => {}; +export const value = 'value 3'; +console.log(Foo, value); diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/main.js b/test/form/samples/jsx/transpiles-jsx-attributes/main.js new file mode 100644 index 00000000000..3748b4076f4 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-attributes/main.js @@ -0,0 +1,5 @@ +import './dep1.js'; +import { Foo, value } from './dep2.js'; +import './dep3.js'; + +export const result = fragment=<> />; diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js deleted file mode 100644 index b73e9ca7247..00000000000 --- a/test/form/samples/jsx/transpiles-jsx-with-attributes/_expected.js +++ /dev/null @@ -1,15 +0,0 @@ -import react from 'react'; - -const value$2 = 'value 1'; -console.log(value$2); - -const value$1 = 'value 2'; -console.log(value$1); - -const value = 'value 3'; -console.log(value); - -const Foo = () => {}; -const result = /*#__PURE__*/react.createElement(Foo, { bar: true, baz: "string", "quux-nix": value$1 }); - -export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/dep1.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/dep1.js deleted file mode 100644 index 1aa687cc2da..00000000000 --- a/test/form/samples/jsx/transpiles-jsx-with-attributes/dep1.js +++ /dev/null @@ -1,2 +0,0 @@ -export const value = 'value 1'; -console.log(value); diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/dep2.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/dep2.js deleted file mode 100644 index 55685c09285..00000000000 --- a/test/form/samples/jsx/transpiles-jsx-with-attributes/dep2.js +++ /dev/null @@ -1,2 +0,0 @@ -export const value = 'value 2'; -console.log(value); diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/dep3.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/dep3.js deleted file mode 100644 index 5a85502eebf..00000000000 --- a/test/form/samples/jsx/transpiles-jsx-with-attributes/dep3.js +++ /dev/null @@ -1,2 +0,0 @@ -export const value = 'value 3'; -console.log(value); diff --git a/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js b/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js deleted file mode 100644 index d2c0720a11d..00000000000 --- a/test/form/samples/jsx/transpiles-jsx-with-attributes/main.js +++ /dev/null @@ -1,6 +0,0 @@ -import './dep1.js'; -import { value } from './dep2.js'; -import './dep3.js'; - -const Foo = () => {}; -export const result = ; From 634ddd4093cbc13747b3cdafaed7c85e6281449c Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 13 May 2024 09:18:27 +0200 Subject: [PATCH 27/62] Support JSXMemberExpression --- rust/parse_ast/src/convert_ast/converter.rs | 59 +++++++++++++++---- .../convert_ast/converter/ast_constants.rs | 41 +++++++------ .../src/convert_ast/converter/ast_macros.rs | 48 +++++++-------- scripts/ast-types.js | 8 +++ src/ast/bufferParsers.ts | 8 +++ src/ast/childNodeKeys.ts | 1 + src/ast/nodes/JSXIdentifier.ts | 4 ++ src/ast/nodes/JSXMemberExpression.ts | 9 +++ src/ast/nodes/NodeType.ts | 2 + src/ast/nodes/index.ts | 2 + src/utils/bufferToAst.ts | 10 ++++ .../_config.js | 8 +++ .../_expected.js | 9 +++ .../preserves-jsx-member-expression/main.js | 7 +++ .../_config.js | 8 +++ .../_expected.js | 11 ++++ .../transpiles-jsx-member-expression/main.js | 7 +++ 17 files changed, 188 insertions(+), 54 deletions(-) create mode 100644 src/ast/nodes/JSXMemberExpression.ts create mode 100644 test/form/samples/jsx/preserves-jsx-member-expression/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-member-expression/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-member-expression/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-member-expression/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-member-expression/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-member-expression/main.js diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index aaef51332b4..81e5e6d99e9 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -3,9 +3,10 @@ use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, JSXClosingElement, JSXClosingFragment, JSXElement, JSXElementChild, JSXElementName, JSXEmptyExpr, - JSXExpr, JSXExprContainer, JSXFragment, JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, - JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, - ParenExpr, Pat, Program, PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, + JSXExpr, JSXExprContainer, JSXFragment, JSXMemberExpr, JSXNamespacedName, JSXObject, + JSXOpeningElement, JSXOpeningFragment, JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, + NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, + SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; @@ -20,15 +21,18 @@ use crate::convert_ast::converter::ast_constants::{ JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET, JSX_EXPRESSION_CONTAINER_RESERVED_BYTES, JSX_FRAGMENT_CHILDREN_OFFSET, JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET, JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET, JSX_FRAGMENT_RESERVED_BYTES, JSX_IDENTIFIER_NAME_OFFSET, - JSX_IDENTIFIER_RESERVED_BYTES, JSX_NAMESPACED_NAME_NAME_OFFSET, - JSX_NAMESPACED_NAME_NAMESPACE_OFFSET, JSX_NAMESPACED_NAME_RESERVED_BYTES, - JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, - JSX_OPENING_ELEMENT_RESERVED_BYTES, JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_TEXT_RAW_OFFSET, - JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, + JSX_IDENTIFIER_RESERVED_BYTES, JSX_MEMBER_EXPRESSION_OBJECT_OFFSET, + JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET, JSX_MEMBER_EXPRESSION_RESERVED_BYTES, + JSX_NAMESPACED_NAME_NAME_OFFSET, JSX_NAMESPACED_NAME_NAMESPACE_OFFSET, + JSX_NAMESPACED_NAME_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, + JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, + JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_TEXT_RAW_OFFSET, JSX_TEXT_RESERVED_BYTES, + JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_CLOSING_ELEMENT, TYPE_JSX_CLOSING_FRAGMENT, TYPE_JSX_ELEMENT, TYPE_JSX_EMPTY_EXPRESSION, - TYPE_JSX_EXPRESSION_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, TYPE_JSX_NAMESPACED_NAME, - TYPE_JSX_OPENING_ELEMENT, TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_TEXT, + TYPE_JSX_EXPRESSION_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, + TYPE_JSX_MEMBER_EXPRESSION, TYPE_JSX_NAMESPACED_NAME, TYPE_JSX_OPENING_ELEMENT, + TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_TEXT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -492,8 +496,8 @@ impl<'a> AstConverter<'a> { JSXElementName::Ident(identifier) => { self.store_jsx_identifier(&identifier.span, &identifier.sym) } - JSXElementName::JSXMemberExpr(_jsx_member_expression) => { - unimplemented!("JSXElementName::JSXMemberExpr") + JSXElementName::JSXMemberExpr(jsx_member_expression) => { + self.convert_jsx_member_expression(jsx_member_expression); } JSXElementName::JSXNamespacedName(_jsx_namespaced_name) => { unimplemented!("JSXElementName::JSXNamespacedName") @@ -501,6 +505,17 @@ impl<'a> AstConverter<'a> { } } + fn convert_jsx_object(&mut self, jsx_object: &JSXObject) { + match jsx_object { + JSXObject::JSXMemberExpr(jsx_member_expression) => { + self.convert_jsx_member_expression(jsx_member_expression); + } + JSXObject::Ident(identifier) => { + self.store_jsx_identifier(&identifier.span, &identifier.sym); + } + } + } + fn convert_literal(&mut self, literal: &Lit) { match literal { Lit::BigInt(bigint_literal) => self.store_literal_bigint(bigint_literal), @@ -888,6 +903,26 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, span); } + fn convert_jsx_member_expression(&mut self, jsx_member_expression: &JSXMemberExpr) { + let end_position = self.add_type_and_start( + &TYPE_JSX_MEMBER_EXPRESSION, + &jsx_member_expression.span, + JSX_MEMBER_EXPRESSION_RESERVED_BYTES, + false, + ); + // object + self.update_reference_position(end_position + JSX_MEMBER_EXPRESSION_OBJECT_OFFSET); + self.convert_jsx_object(&jsx_member_expression.obj); + // property + self.update_reference_position(end_position + JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET); + self.store_jsx_identifier( + &jsx_member_expression.prop.span, + &jsx_member_expression.prop.sym, + ); + // end + self.add_end(end_position, &jsx_member_expression.span); + } + fn convert_jsx_namespaced_name(&mut self, jsx_namespaced_name: &JSXNamespacedName) { let end_position = self.add_type_and_start( &TYPE_JSX_NAMESPACED_NAME, diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index cab53fd03c5..dd32a80fa28 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -32,24 +32,25 @@ pub const TYPE_JSX_EMPTY_EXPRESSION: [u8; 4] = 46u32.to_ne_bytes(); pub const TYPE_JSX_EXPRESSION_CONTAINER: [u8; 4] = 47u32.to_ne_bytes(); pub const TYPE_JSX_FRAGMENT: [u8; 4] = 48u32.to_ne_bytes(); pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 49u32.to_ne_bytes(); -pub const TYPE_JSX_NAMESPACED_NAME: [u8; 4] = 50u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 51u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 52u32.to_ne_bytes(); -pub const TYPE_JSX_TEXT: [u8; 4] = 53u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 61u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 62u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 63u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 64u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 65u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 69u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 70u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 71u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 72u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 75u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 82u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 85u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 88u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 89u32.to_ne_bytes(); +pub const TYPE_JSX_MEMBER_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); +pub const TYPE_JSX_NAMESPACED_NAME: [u8; 4] = 51u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 52u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 53u32.to_ne_bytes(); +pub const TYPE_JSX_TEXT: [u8; 4] = 54u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 62u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 63u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 65u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 66u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 70u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 71u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 72u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 73u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 76u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 83u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 86u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 89u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 90u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -164,6 +165,10 @@ pub const JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET: usize = 12; pub const JSX_IDENTIFIER_RESERVED_BYTES: usize = 8; pub const JSX_IDENTIFIER_NAME_OFFSET: usize = 4; +pub const JSX_MEMBER_EXPRESSION_RESERVED_BYTES: usize = 12; +pub const JSX_MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 4; +pub const JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 8; + pub const JSX_NAMESPACED_NAME_RESERVED_BYTES: usize = 12; pub const JSX_NAMESPACED_NAME_NAMESPACE_OFFSET: usize = 4; pub const JSX_NAMESPACED_NAME_NAME_OFFSET: usize = 8; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index 64b555fcf1b..fef9507d13a 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -319,7 +319,7 @@ macro_rules! store_import_specifier { macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&54u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &56u32.to_ne_bytes(), + &57u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&66u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&73u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&80u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&80u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &81u32.to_ne_bytes(), + &82u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&83u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&84u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&84u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&85u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&86u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&87u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &87u32.to_ne_bytes(), + &88u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&90u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&91u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &91u32.to_ne_bytes(), + &92u32.to_ne_bytes(), &$span, 12, false, diff --git a/scripts/ast-types.js b/scripts/ast-types.js index bbac2d5be41..beaf6d6c648 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -439,6 +439,14 @@ export const AST_NODES = { fields: [['name', 'String']], useMacro: false }, + JSXMemberExpression: { + estreeType: 'any', + fields: [ + ['object', 'Node'], + ['property', 'Node'] + ], + useMacro: false + }, JSXNamespacedName: { estreeType: 'any', fields: [ diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index 53c7f54cad4..44042b61155 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -56,6 +56,7 @@ import JSXEmptyExpression from './nodes/JSXEmptyExpression'; import JSXExpressionContainer from './nodes/JSXExpressionContainer'; import JSXFragment from './nodes/JSXFragment'; import JSXIdentifier from './nodes/JSXIdentifier'; +import JSXMemberExpression from './nodes/JSXMemberExpression'; import JSXNamespacedName from './nodes/JSXNamespacedName'; import JSXOpeningElement from './nodes/JSXOpeningElement'; import JSXOpeningFragment from './nodes/JSXOpeningFragment'; @@ -161,6 +162,7 @@ const nodeTypeStrings = [ 'JSXExpressionContainer', 'JSXFragment', 'JSXIdentifier', + 'JSXMemberExpression', 'JSXNamespacedName', 'JSXOpeningElement', 'JSXOpeningFragment', @@ -256,6 +258,7 @@ const nodeConstructors: (typeof NodeBase)[] = [ JSXExpressionContainer, JSXFragment, JSXIdentifier, + JSXMemberExpression, JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, @@ -634,6 +637,11 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ function jsxIdentifier(node: JSXIdentifier, position, buffer) { node.name = buffer.convertString(buffer[position]); }, + function jsxMemberExpression(node: JSXMemberExpression, position, buffer) { + const { scope } = node; + node.object = convertNode(node, scope, buffer[position], buffer); + node.property = convertNode(node, scope, buffer[position + 1], buffer); + }, function jsxNamespacedName(node: JSXNamespacedName, position, buffer) { const { scope } = node; node.namespace = convertNode(node, scope, buffer[position], buffer); diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index 9ae1a126001..bd96914f8d7 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -49,6 +49,7 @@ export const childNodeKeys: Record = { JSXExpressionContainer: ['expression'], JSXFragment: ['openingFragment', 'children', 'closingFragment'], JSXIdentifier: [], + JSXMemberExpression: ['object', 'property'], JSXNamespacedName: ['namespace', 'name'], JSXOpeningElement: ['name', 'attributes'], JSXOpeningFragment: [], diff --git a/src/ast/nodes/JSXIdentifier.ts b/src/ast/nodes/JSXIdentifier.ts index 7d6efb0ef38..868571d9656 100644 --- a/src/ast/nodes/JSXIdentifier.ts +++ b/src/ast/nodes/JSXIdentifier.ts @@ -1,5 +1,6 @@ import type MagicString from 'magic-string'; import type { RenderOptions } from '../../utils/renderHelpers'; +import type JSXMemberExpression from './JSXMemberExpression'; import type JSXOpeningElement from './JSXOpeningElement'; import type * as NodeType from './NodeType'; import IdentifierBase from './shared/IdentifierBase'; @@ -37,6 +38,9 @@ export default class JSXIdentifier extends IdentifierBase { case 'JSXClosingElement': { return (this.parent as JSXOpeningElement).name === this; } + case 'JSXMemberExpression': { + return (this.parent as JSXMemberExpression).object === this; + } case 'JSXAttribute': case 'JSXNamespacedName': { return false; diff --git a/src/ast/nodes/JSXMemberExpression.ts b/src/ast/nodes/JSXMemberExpression.ts new file mode 100644 index 00000000000..1212066f3c7 --- /dev/null +++ b/src/ast/nodes/JSXMemberExpression.ts @@ -0,0 +1,9 @@ +import type JSXIdentifier from './JSXIdentifier'; +import type * as NodeType from './NodeType'; +import { NodeBase } from './shared/Node'; + +export default class JSXMemberExpression extends NodeBase { + type!: NodeType.tJSXMemberExpression; + object!: JSXMemberExpression | JSXIdentifier; + property!: JSXIdentifier; +} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index a17e8946ba0..7881f9716ed 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -48,6 +48,7 @@ export type tJSXEmptyExpression = 'JSXEmptyExpression'; export type tJSXExpressionContainer = 'JSXExpressionContainer'; export type tJSXFragment = 'JSXFragment'; export type tJSXIdentifier = 'JSXIdentifier'; +export type tJSXMemberExpression = 'JSXMemberExpression'; export type tJSXNamespacedName = 'JSXNamespacedName'; export type tJSXOpeningElement = 'JSXOpeningElement'; export type tJSXOpeningFragment = 'JSXOpeningFragment'; @@ -135,6 +136,7 @@ export const JSXEmptyExpression: tJSXEmptyExpression = 'JSXEmptyExpression'; export const JSXExpressionContainer: tJSXExpressionContainer = 'JSXExpressionContainer'; export const JSXFragment: tJSXFragment = 'JSXFragment'; export const JSXIdentifier: tJSXIdentifier = 'JSXIdentifier'; +export const JSXMemberExpression: tJSXMemberExpression = 'JSXMemberExpression'; export const JSXNamespacedName: tJSXNamespacedName = 'JSXNamespacedName'; export const JSXOpeningElement: tJSXOpeningElement = 'JSXOpeningElement'; export const JSXOpeningFragment: tJSXOpeningFragment = 'JSXOpeningFragment'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 2981e7e839b..57629a226f5 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -48,6 +48,7 @@ import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; import JSXFragment from './JSXFragment'; import JSXIdentifier from './JSXIdentifier'; +import JSXMemberExpression from './JSXMemberExpression'; import JSXNamespacedName from './JSXNamespacedName'; import JSXOpeningElement from './JSXOpeningElement'; import JSXOpeningFragment from './JSXOpeningFragment'; @@ -138,6 +139,7 @@ export const nodeConstructors: Record = { JSXExpressionContainer, JSXFragment, JSXIdentifier, + JSXMemberExpression, JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index fea7363bd7a..2b4232a30d8 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -520,6 +520,15 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ name: buffer.convertString(buffer[position + 2]) }; }, + function jsxMemberExpression(position, buffer): JSXMemberExpressionNode { + return { + type: 'JSXMemberExpression', + start: buffer[position], + end: buffer[position + 1], + object: convertNode(buffer[position + 2], buffer), + property: convertNode(buffer[position + 3], buffer) + }; + }, function jsxNamespacedName(position, buffer): JSXNamespacedNameNode { return { type: 'JSXNamespacedName', @@ -1011,6 +1020,7 @@ export type JSXEmptyExpressionNode = RollupAstNode; export type JSXExpressionContainerNode = RollupAstNode; export type JSXFragmentNode = RollupAstNode; export type JSXIdentifierNode = RollupAstNode; +export type JSXMemberExpressionNode = RollupAstNode; export type JSXNamespacedNameNode = RollupAstNode; export type JSXOpeningElementNode = RollupAstNode; export type JSXOpeningFragmentNode = RollupAstNode; diff --git a/test/form/samples/jsx/preserves-jsx-member-expression/_config.js b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js new file mode 100644 index 00000000000..23e0249f6ba --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX member expressions', + options: { + external: ['react'], + jsx: 'preserve' + } +}); diff --git a/test/form/samples/jsx/preserves-jsx-member-expression/_expected.js b/test/form/samples/jsx/preserves-jsx-member-expression/_expected.js new file mode 100644 index 00000000000..e4db00ef475 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-member-expression/_expected.js @@ -0,0 +1,9 @@ +const obj = { + Foo: () => {}, + bar: { Baz: () => {} } +}; + +const result1 = ; +const result2 = ; + +export { result1, result2 }; diff --git a/test/form/samples/jsx/preserves-jsx-member-expression/main.js b/test/form/samples/jsx/preserves-jsx-member-expression/main.js new file mode 100644 index 00000000000..04e40c09d07 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-member-expression/main.js @@ -0,0 +1,7 @@ +const obj = { + Foo: () => {}, + bar: { Baz: () => {} } +}; + +export const result1 = ; +export const result2 = ; diff --git a/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js new file mode 100644 index 00000000000..b3c5bfcd03a --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX member expressions', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-member-expression/_expected.js b/test/form/samples/jsx/transpiles-jsx-member-expression/_expected.js new file mode 100644 index 00000000000..7549595c533 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-member-expression/_expected.js @@ -0,0 +1,11 @@ +import react from 'react'; + +const obj = { + Foo: () => {}, + bar: { Baz: () => {} } +}; + +const result1 = /*#__PURE__*/react.createElement(obj.Foo, null); +const result2 = /*#__PURE__*/react.createElement(obj.bar.Baz, null); + +export { result1, result2 }; diff --git a/test/form/samples/jsx/transpiles-jsx-member-expression/main.js b/test/form/samples/jsx/transpiles-jsx-member-expression/main.js new file mode 100644 index 00000000000..04e40c09d07 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-member-expression/main.js @@ -0,0 +1,7 @@ +const obj = { + Foo: () => {}, + bar: { Baz: () => {} } +}; + +export const result1 = ; +export const result2 = ; From c240f3f763f796cc421ecd799e53cf19d5070947 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 13 May 2024 21:30:39 +0200 Subject: [PATCH 28/62] Support JSXSpreadChild --- rust/parse_ast/src/convert_ast/converter.rs | 29 ++++++++--- .../convert_ast/converter/ast_constants.rs | 34 +++++++------ .../src/convert_ast/converter/ast_macros.rs | 48 +++++++++---------- scripts/ast-types.js | 5 ++ src/ast/bufferParsers.ts | 7 +++ src/ast/childNodeKeys.ts | 1 + src/ast/nodes/JSXClosingElement.ts | 4 +- src/ast/nodes/JSXElement.ts | 8 +--- src/ast/nodes/JSXFragment.ts | 8 +--- src/ast/nodes/JSXOpeningElement.ts | 12 +++-- src/ast/nodes/JSXSpreadChild.ts | 20 ++++++++ src/ast/nodes/NodeType.ts | 2 + src/ast/nodes/index.ts | 2 + src/utils/bufferToAst.ts | 9 ++++ .../jsx/preserves-jsx-spread-child/_config.js | 10 ++++ .../preserves-jsx-spread-child/_expected.js | 14 ++++++ .../jsx/preserves-jsx-spread-child/dep1.js | 2 + .../jsx/preserves-jsx-spread-child/dep2.js | 2 + .../jsx/preserves-jsx-spread-child/dep3.js | 2 + .../jsx/preserves-jsx-spread-child/main.js | 6 +++ .../transpiles-jsx-spread-child/_config.js | 10 ++++ .../transpiles-jsx-spread-child/_expected.js | 16 +++++++ .../jsx/transpiles-jsx-spread-child/dep1.js | 2 + .../jsx/transpiles-jsx-spread-child/dep2.js | 2 + .../jsx/transpiles-jsx-spread-child/dep3.js | 2 + .../jsx/transpiles-jsx-spread-child/main.js | 6 +++ 26 files changed, 199 insertions(+), 64 deletions(-) create mode 100644 src/ast/nodes/JSXSpreadChild.ts create mode 100644 test/form/samples/jsx/preserves-jsx-spread-child/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-child/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-child/dep1.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-child/dep2.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-child/dep3.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-child/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-child/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-child/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-child/dep1.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-child/dep2.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-child/dep3.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-child/main.js diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 81e5e6d99e9..af1314b1a15 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -4,9 +4,9 @@ use swc_ecma_ast::{ ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, JSXClosingElement, JSXClosingFragment, JSXElement, JSXElementChild, JSXElementName, JSXEmptyExpr, JSXExpr, JSXExprContainer, JSXFragment, JSXMemberExpr, JSXNamespacedName, JSXObject, - JSXOpeningElement, JSXOpeningFragment, JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, - NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, - SimpleAssignTarget, Stmt, VarDeclOrExpr, + JSXOpeningElement, JSXOpeningFragment, JSXSpreadChild, JSXText, Lit, ModuleDecl, + ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, + PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; @@ -26,13 +26,14 @@ use crate::convert_ast::converter::ast_constants::{ JSX_NAMESPACED_NAME_NAME_OFFSET, JSX_NAMESPACED_NAME_NAMESPACE_OFFSET, JSX_NAMESPACED_NAME_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, - JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_TEXT_RAW_OFFSET, JSX_TEXT_RESERVED_BYTES, + JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_SPREAD_CHILD_EXPRESSION_OFFSET, + JSX_SPREAD_CHILD_RESERVED_BYTES, JSX_TEXT_RAW_OFFSET, JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_CLOSING_ELEMENT, TYPE_JSX_CLOSING_FRAGMENT, TYPE_JSX_ELEMENT, TYPE_JSX_EMPTY_EXPRESSION, TYPE_JSX_EXPRESSION_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, TYPE_JSX_MEMBER_EXPRESSION, TYPE_JSX_NAMESPACED_NAME, TYPE_JSX_OPENING_ELEMENT, - TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_TEXT, + TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_SPREAD_CHILD, TYPE_JSX_TEXT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -479,8 +480,8 @@ impl<'a> AstConverter<'a> { JSXElementChild::JSXExprContainer(jsx_expr_container) => { self.convert_jsx_expression_container(jsx_expr_container); } - JSXElementChild::JSXSpreadChild(_jsx_spread_child) => { - unimplemented!("JSXElementChild::JSXSpreadChild") + JSXElementChild::JSXSpreadChild(jsx_spread_child) => { + self.convert_jsx_spread_child(jsx_spread_child); } JSXElementChild::JSXFragment(jsx_fragment) => { self.convert_jsx_fragment(jsx_fragment); @@ -983,6 +984,20 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &jsxopening_fragment.span); } + fn convert_jsx_spread_child(&mut self, jsx_spread_child: &JSXSpreadChild) { + let end_position = self.add_type_and_start( + &TYPE_JSX_SPREAD_CHILD, + &jsx_spread_child.span, + JSX_SPREAD_CHILD_RESERVED_BYTES, + false, + ); + // expression + self.update_reference_position(end_position + JSX_SPREAD_CHILD_EXPRESSION_OFFSET); + self.convert_expression(&jsx_spread_child.expr); + // end + self.add_end(end_position, &jsx_spread_child.span); + } + fn convert_jsx_text(&mut self, jsx_text: &JSXText) { let end_position = self.add_type_and_start( &TYPE_JSX_TEXT, diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index dd32a80fa28..d0bac74589e 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -36,21 +36,22 @@ pub const TYPE_JSX_MEMBER_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); pub const TYPE_JSX_NAMESPACED_NAME: [u8; 4] = 51u32.to_ne_bytes(); pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 52u32.to_ne_bytes(); pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 53u32.to_ne_bytes(); -pub const TYPE_JSX_TEXT: [u8; 4] = 54u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 62u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 63u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 64u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 65u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 66u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 70u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 71u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 72u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 73u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 76u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 83u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 86u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 89u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 90u32.to_ne_bytes(); +pub const TYPE_JSX_SPREAD_CHILD: [u8; 4] = 54u32.to_ne_bytes(); +pub const TYPE_JSX_TEXT: [u8; 4] = 55u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 63u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 65u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 66u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 67u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 71u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 72u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 73u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 74u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 77u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 84u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 87u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 90u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 91u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -179,6 +180,9 @@ pub const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; pub const JSX_OPENING_FRAGMENT_RESERVED_BYTES: usize = 4; +pub const JSX_SPREAD_CHILD_RESERVED_BYTES: usize = 8; +pub const JSX_SPREAD_CHILD_EXPRESSION_OFFSET: usize = 4; + pub const JSX_TEXT_RESERVED_BYTES: usize = 12; pub const JSX_TEXT_VALUE_OFFSET: usize = 4; pub const JSX_TEXT_RAW_OFFSET: usize = 8; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index fef9507d13a..8a5df29939b 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -319,7 +319,7 @@ macro_rules! store_import_specifier { macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &57u32.to_ne_bytes(), + &58u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&62u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&67u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&70u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&74u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&80u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&80u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&82u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &82u32.to_ne_bytes(), + &83u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&84u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&85u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&85u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&86u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&87u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&88u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &88u32.to_ne_bytes(), + &89u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&91u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&92u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &92u32.to_ne_bytes(), + &93u32.to_ne_bytes(), &$span, 12, false, diff --git a/scripts/ast-types.js b/scripts/ast-types.js index beaf6d6c648..156f0428153 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -472,6 +472,11 @@ export const AST_NODES = { estreeType: 'any', useMacro: false }, + JSXSpreadChild: { + estreeType: 'any', + fields: [['expression', 'Node']], + useMacro: false + }, JSXText: { estreeType: 'any', fields: [ diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index 44042b61155..aae5452a141 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -60,6 +60,7 @@ import JSXMemberExpression from './nodes/JSXMemberExpression'; import JSXNamespacedName from './nodes/JSXNamespacedName'; import JSXOpeningElement from './nodes/JSXOpeningElement'; import JSXOpeningFragment from './nodes/JSXOpeningFragment'; +import JSXSpreadChild from './nodes/JSXSpreadChild'; import JSXText from './nodes/JSXText'; import LabeledStatement from './nodes/LabeledStatement'; import Literal from './nodes/Literal'; @@ -166,6 +167,7 @@ const nodeTypeStrings = [ 'JSXNamespacedName', 'JSXOpeningElement', 'JSXOpeningFragment', + 'JSXSpreadChild', 'JSXText', 'LabeledStatement', 'Literal', @@ -262,6 +264,7 @@ const nodeConstructors: (typeof NodeBase)[] = [ JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, + JSXSpreadChild, JSXText, LabeledStatement, Literal, @@ -658,6 +661,10 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ node.attributes = []; node.selfClosing = false; }, + function jsxSpreadChild(node: JSXSpreadChild, position, buffer) { + const { scope } = node; + node.expression = convertNode(node, scope, buffer[position], buffer); + }, function jsxText(node: JSXText, position, buffer) { node.value = buffer.convertString(buffer[position]); node.raw = buffer.convertString(buffer[position + 1]); diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index bd96914f8d7..fa05838a7c3 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -53,6 +53,7 @@ export const childNodeKeys: Record = { JSXNamespacedName: ['namespace', 'name'], JSXOpeningElement: ['name', 'attributes'], JSXOpeningFragment: [], + JSXSpreadChild: ['expression'], JSXText: [], LabeledStatement: ['label', 'body'], Literal: [], diff --git a/src/ast/nodes/JSXClosingElement.ts b/src/ast/nodes/JSXClosingElement.ts index 1af7441d2ff..8fdd4500943 100644 --- a/src/ast/nodes/JSXClosingElement.ts +++ b/src/ast/nodes/JSXClosingElement.ts @@ -1,8 +1,10 @@ import type JSXIdentifier from './JSXIdentifier'; +import type JSXMemberExpression from './JSXMemberExpression'; +import type JSXNamespacedName from './JSXNamespacedName'; import type * as NodeType from './NodeType'; import JSXClosingBase from './shared/JSXClosingBase'; export default class JSXClosingElement extends JSXClosingBase { type!: NodeType.tJSXClosingElement; - name!: JSXIdentifier /* TODO | JSXMemberExpression | JSXNamespacedName */; + name!: JSXIdentifier | JSXMemberExpression | JSXNamespacedName; } diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index b5c7900f2dd..ffb77d84b11 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -6,6 +6,7 @@ import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; import type JSXFragment from './JSXFragment'; import type JSXOpeningElement from './JSXOpeningElement'; +import type JSXSpreadChild from './JSXSpreadChild'; import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; @@ -14,12 +15,7 @@ export default class JSXElement extends NodeBase { type!: NodeType.tJSXElement; openingElement!: JSXOpeningElement; closingElement!: JSXClosingElement | null; - children!: ( - | JSXText - | JSXExpressionContainer - | JSXElement - | JSXFragment - ) /* TODO | JSXSpreadChild */[]; + children!: (JSXText | JSXExpressionContainer | JSXElement | JSXFragment | JSXSpreadChild)[]; render(code: MagicString, options: RenderOptions): void { const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index 5bc5849aba9..5c287c2670a 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -7,6 +7,7 @@ import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; import type JSXFragment from './JSXFragment'; import type JSXOpeningFragment from './JSXOpeningFragment'; +import type JSXSpreadChild from './JSXSpreadChild'; import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; @@ -14,12 +15,7 @@ import { NodeBase } from './shared/Node'; export default class JsxElement extends NodeBase { type!: NodeType.tJSXElement; openingFragment!: JSXOpeningFragment; - children!: ( - | JSXText - | JSXExpressionContainer /* TODO | JSXSpreadChild */ - | JSXElement - | JSXFragment - )[]; + children!: (JSXText | JSXExpressionContainer | JSXSpreadChild | JSXElement | JSXFragment)[]; closingFragment!: JSXClosingFragment; render(code: MagicString, options: RenderOptions): void { diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index 8108c2ea987..f15e471b99a 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -3,23 +3,25 @@ import type { NormalizedJsxOptions } from '../../rollup/types'; import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXAttribute from './JSXAttribute'; import type JSXIdentifier from './JSXIdentifier'; +import type JSXMemberExpression from './JSXMemberExpression'; +import type JSXNamespacedName from './JSXNamespacedName'; import type * as NodeType from './NodeType'; import JSXOpeningBase from './shared/JSXOpeningBase'; export default class JSXOpeningElement extends JSXOpeningBase { type!: NodeType.tJSXOpeningElement; - name!: JSXIdentifier; /* TODO | JSXMemberExpression | JSXNamespacedName; */ + name!: JSXIdentifier | JSXMemberExpression | JSXNamespacedName; attributes!: JSXAttribute /* TODO | JSXSpreadAttribute */[]; selfClosing!: boolean; render(code: MagicString, options: RenderOptions): void { super.render(code, options); - const { - snippets: { getPropertyAccess }, - useOriginalName - } = options; const { factory, preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; if (!preserve) { + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; const [, ...nestedName] = factory.split('.'); code.overwrite( this.start, diff --git a/src/ast/nodes/JSXSpreadChild.ts b/src/ast/nodes/JSXSpreadChild.ts new file mode 100644 index 00000000000..d8594f4fa37 --- /dev/null +++ b/src/ast/nodes/JSXSpreadChild.ts @@ -0,0 +1,20 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; +import type { RenderOptions } from '../../utils/renderHelpers'; +import type * as NodeType from './NodeType'; +import type { ExpressionNode } from './shared/Node'; +import { NodeBase } from './shared/Node'; + +export default class JSXSpreadChild extends NodeBase { + type!: NodeType.tJSXSpreadChild; + expression!: ExpressionNode; + + render(code: MagicString, options: RenderOptions): void { + super.render(code, options); + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + code.overwrite(this.start, this.expression.start, '...', { contentOnly: true }); + code.overwrite(this.expression.end, this.end, '', { contentOnly: true }); + } + } +} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index 7881f9716ed..f7fae2695a2 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -52,6 +52,7 @@ export type tJSXMemberExpression = 'JSXMemberExpression'; export type tJSXNamespacedName = 'JSXNamespacedName'; export type tJSXOpeningElement = 'JSXOpeningElement'; export type tJSXOpeningFragment = 'JSXOpeningFragment'; +export type tJSXSpreadChild = 'JSXSpreadChild'; export type tJSXText = 'JSXText'; export type tLabeledStatement = 'LabeledStatement'; export type tLiteral = 'Literal'; @@ -140,6 +141,7 @@ export const JSXMemberExpression: tJSXMemberExpression = 'JSXMemberExpression'; export const JSXNamespacedName: tJSXNamespacedName = 'JSXNamespacedName'; export const JSXOpeningElement: tJSXOpeningElement = 'JSXOpeningElement'; export const JSXOpeningFragment: tJSXOpeningFragment = 'JSXOpeningFragment'; +export const JSXSpreadChild: tJSXSpreadChild = 'JSXSpreadChild'; export const JSXText: tJSXText = 'JSXText'; export const LabeledStatement: tLabeledStatement = 'LabeledStatement'; export const Literal: tLiteral = 'Literal'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 57629a226f5..1d1d3cc47a7 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -52,6 +52,7 @@ import JSXMemberExpression from './JSXMemberExpression'; import JSXNamespacedName from './JSXNamespacedName'; import JSXOpeningElement from './JSXOpeningElement'; import JSXOpeningFragment from './JSXOpeningFragment'; +import JSXSpreadChild from './JSXSpreadChild'; import JSXText from './JSXText'; import LabeledStatement from './LabeledStatement'; import Literal from './Literal'; @@ -143,6 +144,7 @@ export const nodeConstructors: Record = { JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, + JSXSpreadChild, JSXText, LabeledStatement, Literal, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index 2b4232a30d8..71e6405f2a7 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -558,6 +558,14 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ selfClosing: false }; }, + function jsxSpreadChild(position, buffer): JSXSpreadChildNode { + return { + type: 'JSXSpreadChild', + start: buffer[position], + end: buffer[position + 1], + expression: convertNode(buffer[position + 2], buffer) + }; + }, function jsxText(position, buffer): JSXTextNode { return { type: 'JSXText', @@ -1024,6 +1032,7 @@ export type JSXMemberExpressionNode = RollupAstNode; export type JSXNamespacedNameNode = RollupAstNode; export type JSXOpeningElementNode = RollupAstNode; export type JSXOpeningFragmentNode = RollupAstNode; +export type JSXSpreadChildNode = RollupAstNode; export type JSXTextNode = RollupAstNode; export type LabeledStatementNode = RollupAstNode; export type LiteralBigIntNode = RollupAstNode; diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/_config.js b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js new file mode 100644 index 00000000000..a9ea396f4d2 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX spread children', + options: { + external: ['react'], + jsx: 'preserve' + }, + // apparently, acorn-jsx does not support spread children + verifyAst: false +}); diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/_expected.js b/test/form/samples/jsx/preserves-jsx-spread-child/_expected.js new file mode 100644 index 00000000000..139d1277ca3 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-child/_expected.js @@ -0,0 +1,14 @@ +const spread$2 = ['spread 1']; +console.log(spread$2); + +const spread$1 = ['spread 2']; +console.log(spread$1); + +const spread = ['spread 3']; +console.log(spread); + +const Foo = () => {}; +const element = {...spread$1}; +const fragment = <>{...spread$1}; + +export { element, fragment }; diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/dep1.js b/test/form/samples/jsx/preserves-jsx-spread-child/dep1.js new file mode 100644 index 00000000000..53572b805ec --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-child/dep1.js @@ -0,0 +1,2 @@ +export const spread = ['spread 1']; +console.log(spread); diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/dep2.js b/test/form/samples/jsx/preserves-jsx-spread-child/dep2.js new file mode 100644 index 00000000000..bbea244bcfb --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-child/dep2.js @@ -0,0 +1,2 @@ +export const spread = ['spread 2']; +console.log(spread); diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/dep3.js b/test/form/samples/jsx/preserves-jsx-spread-child/dep3.js new file mode 100644 index 00000000000..666d48094d1 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-child/dep3.js @@ -0,0 +1,2 @@ +export const spread = ['spread 3']; +console.log(spread); diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/main.js b/test/form/samples/jsx/preserves-jsx-spread-child/main.js new file mode 100644 index 00000000000..10e217564e0 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-child/main.js @@ -0,0 +1,6 @@ +import './dep1.js'; +import { spread } from './dep2.js'; +import './dep3.js'; +const Foo = () => {}; +export const element = {...spread}; +export const fragment = <>{...spread}; diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js new file mode 100644 index 00000000000..f744d02197b --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js @@ -0,0 +1,10 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX spread children', + options: { + external: ['react'], + jsx: 'react' + }, + // apparently, acorn-jsx does not support spread children + verifyAst: false +}); diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/_expected.js b/test/form/samples/jsx/transpiles-jsx-spread-child/_expected.js new file mode 100644 index 00000000000..9a1f05f7ff9 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/_expected.js @@ -0,0 +1,16 @@ +import react from 'react'; + +const spread$2 = ['spread 1']; +console.log(spread$2); + +const spread$1 = ['spread 2']; +console.log(spread$1); + +const spread = ['spread 3']; +console.log(spread); + +const Foo = () => {}; +const element = /*#__PURE__*/react.createElement(Foo, null, ...spread$1); +const fragment = /*#__PURE__*/react.createElement(react.Fragment, null, ...spread$1); + +export { element, fragment }; diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/dep1.js b/test/form/samples/jsx/transpiles-jsx-spread-child/dep1.js new file mode 100644 index 00000000000..53572b805ec --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/dep1.js @@ -0,0 +1,2 @@ +export const spread = ['spread 1']; +console.log(spread); diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/dep2.js b/test/form/samples/jsx/transpiles-jsx-spread-child/dep2.js new file mode 100644 index 00000000000..bbea244bcfb --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/dep2.js @@ -0,0 +1,2 @@ +export const spread = ['spread 2']; +console.log(spread); diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/dep3.js b/test/form/samples/jsx/transpiles-jsx-spread-child/dep3.js new file mode 100644 index 00000000000..666d48094d1 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/dep3.js @@ -0,0 +1,2 @@ +export const spread = ['spread 3']; +console.log(spread); diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/main.js b/test/form/samples/jsx/transpiles-jsx-spread-child/main.js new file mode 100644 index 00000000000..10e217564e0 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/main.js @@ -0,0 +1,6 @@ +import './dep1.js'; +import { spread } from './dep2.js'; +import './dep3.js'; +const Foo = () => {}; +export const element = {...spread}; +export const fragment = <>{...spread}; From 9eabdc60d6575331444f5cceb012167057ffd3d1 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Tue, 14 May 2024 21:34:11 +0200 Subject: [PATCH 29/62] Support JSXSpreadAttribute --- rust/parse_ast/src/convert_ast/converter.rs | 50 +++++++++++--- .../convert_ast/converter/ast_constants.rs | 36 +++++----- .../src/convert_ast/converter/ast_macros.rs | 48 ++++++------- scripts/ast-types.js | 5 ++ src/ast/bufferParsers.ts | 7 ++ src/ast/childNodeKeys.ts | 1 + src/ast/nodes/JSXOpeningElement.ts | 67 +++++++++++++++---- src/ast/nodes/JSXSpreadAttribute.ts | 20 ++++++ src/ast/nodes/NodeType.ts | 2 + src/ast/nodes/index.ts | 2 + src/utils/bufferToAst.ts | 9 +++ .../jsx/preserves-jsx-attributes/_expected.js | 8 ++- .../jsx/preserves-jsx-attributes/main.js | 8 ++- .../preserves-jsx-spread-attribute/_config.js | 8 +++ .../_expected.js | 20 ++++++ .../preserves-jsx-spread-attribute/dep1.js | 2 + .../preserves-jsx-spread-attribute/dep2.js | 2 + .../preserves-jsx-spread-attribute/dep3.js | 2 + .../preserves-jsx-spread-attribute/main.js | 13 ++++ .../transpiles-jsx-attributes/_expected.js | 7 +- .../jsx/transpiles-jsx-attributes/main.js | 8 ++- .../_config.js | 8 +++ .../_expected.js | 21 ++++++ .../transpiles-jsx-spread-attribute/dep1.js | 2 + .../transpiles-jsx-spread-attribute/dep2.js | 2 + .../transpiles-jsx-spread-attribute/dep3.js | 2 + .../transpiles-jsx-spread-attribute/main.js | 13 ++++ 27 files changed, 307 insertions(+), 66 deletions(-) create mode 100644 src/ast/nodes/JSXSpreadAttribute.ts create mode 100644 test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-attribute/_expected.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-attribute/dep1.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-attribute/dep2.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-attribute/dep3.js create mode 100644 test/form/samples/jsx/preserves-jsx-spread-attribute/main.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-attribute/_expected.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-attribute/dep1.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-attribute/dep2.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-attribute/dep3.js create mode 100644 test/form/samples/jsx/transpiles-jsx-spread-attribute/main.js diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index af1314b1a15..3ccaf624e82 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,4 +1,4 @@ -use swc_common::Span; +use swc_common::{Span, Spanned}; use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, @@ -6,12 +6,13 @@ use swc_ecma_ast::{ JSXExpr, JSXExprContainer, JSXFragment, JSXMemberExpr, JSXNamespacedName, JSXObject, JSXOpeningElement, JSXOpeningFragment, JSXSpreadChild, JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, - PropName, PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, + PropName, PropOrSpread, SimpleAssignTarget, SpreadElement, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; use crate::ast_nodes::variable_declaration::VariableDeclaration; use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; +use crate::convert_ast::converter::analyze_code::find_first_occurrence_outside_comment; use crate::convert_ast::converter::ast_constants::{ JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_ATTRIBUTE_VALUE_OFFSET, JSX_CLOSING_ELEMENT_NAME_OFFSET, JSX_CLOSING_ELEMENT_RESERVED_BYTES, @@ -26,14 +27,15 @@ use crate::convert_ast::converter::ast_constants::{ JSX_NAMESPACED_NAME_NAME_OFFSET, JSX_NAMESPACED_NAME_NAMESPACE_OFFSET, JSX_NAMESPACED_NAME_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, - JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_SPREAD_CHILD_EXPRESSION_OFFSET, + JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET, + JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES, JSX_SPREAD_CHILD_EXPRESSION_OFFSET, JSX_SPREAD_CHILD_RESERVED_BYTES, JSX_TEXT_RAW_OFFSET, JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_CLOSING_ELEMENT, TYPE_JSX_CLOSING_FRAGMENT, TYPE_JSX_ELEMENT, TYPE_JSX_EMPTY_EXPRESSION, TYPE_JSX_EXPRESSION_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, TYPE_JSX_MEMBER_EXPRESSION, TYPE_JSX_NAMESPACED_NAME, TYPE_JSX_OPENING_ELEMENT, - TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_SPREAD_CHILD, TYPE_JSX_TEXT, + TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_SPREAD_ATTRIBUTE, TYPE_JSX_SPREAD_CHILD, TYPE_JSX_TEXT, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -450,13 +452,17 @@ impl<'a> AstConverter<'a> { } } - fn convert_jsx_attribute_or_spread(&mut self, jsx_attribute_or_spread: &JSXAttrOrSpread) { + fn convert_jsx_attribute_or_spread( + &mut self, + jsx_attribute_or_spread: &JSXAttrOrSpread, + previous_element_end: u32, + ) { match jsx_attribute_or_spread { JSXAttrOrSpread::JSXAttr(jsx_attribute) => { self.convert_jsx_attribute(jsx_attribute); } - JSXAttrOrSpread::SpreadElement(_spread_element) => { - unimplemented!("JSXAttrOrSpread::SpreadElement") + JSXAttrOrSpread::SpreadElement(spread_element) => { + self.convert_jsx_spread_element(spread_element, previous_element_end); } } } @@ -961,11 +967,14 @@ impl<'a> AstConverter<'a> { self.update_reference_position(end_position + JSX_OPENING_ELEMENT_NAME_OFFSET); self.convert_jsx_element_name(&jsx_opening_element.name); // attributes - self.convert_item_list( + let mut previous_element_end = jsx_opening_element.name.span().hi.0; + self.convert_item_list_with_state( &jsx_opening_element.attrs, + &mut previous_element_end, end_position + JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, - |ast_converter, jsx_attribute| { - ast_converter.convert_jsx_attribute_or_spread(jsx_attribute); + |ast_converter, jsx_attribute, previous_end| { + ast_converter.convert_jsx_attribute_or_spread(jsx_attribute, *previous_end); + *previous_end = jsx_attribute.span().hi.0; true }, ); @@ -998,6 +1007,27 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &jsx_spread_child.span); } + fn convert_jsx_spread_element( + &mut self, + spread_element: &SpreadElement, + previous_element_end: u32, + ) { + let end_position = self.add_type_and_explicit_start( + &TYPE_JSX_SPREAD_ATTRIBUTE, + find_first_occurrence_outside_comment(self.code, b'{', previous_element_end), + JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES, + ); + // argument + self.update_reference_position(end_position + JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET); + self.convert_expression(&spread_element.expr); + // end + self.add_explicit_end( + end_position, + find_first_occurrence_outside_comment(self.code, b'}', spread_element.expr.span().hi.0 - 1) + + 1, + ); + } + fn convert_jsx_text(&mut self, jsx_text: &JSXText) { let end_position = self.add_type_and_start( &TYPE_JSX_TEXT, diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index d0bac74589e..0f310097cc6 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -36,22 +36,23 @@ pub const TYPE_JSX_MEMBER_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); pub const TYPE_JSX_NAMESPACED_NAME: [u8; 4] = 51u32.to_ne_bytes(); pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 52u32.to_ne_bytes(); pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 53u32.to_ne_bytes(); -pub const TYPE_JSX_SPREAD_CHILD: [u8; 4] = 54u32.to_ne_bytes(); -pub const TYPE_JSX_TEXT: [u8; 4] = 55u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 63u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 64u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 65u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 66u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 67u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 71u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 72u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 73u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 74u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 77u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 84u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 87u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 90u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 91u32.to_ne_bytes(); +pub const TYPE_JSX_SPREAD_ATTRIBUTE: [u8; 4] = 54u32.to_ne_bytes(); +pub const TYPE_JSX_SPREAD_CHILD: [u8; 4] = 55u32.to_ne_bytes(); +pub const TYPE_JSX_TEXT: [u8; 4] = 56u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 65u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 66u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 67u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 68u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 72u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 73u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 74u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 75u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 78u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 85u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 88u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 91u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 92u32.to_ne_bytes(); pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; @@ -180,6 +181,9 @@ pub const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; pub const JSX_OPENING_FRAGMENT_RESERVED_BYTES: usize = 4; +pub const JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES: usize = 8; +pub const JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET: usize = 4; + pub const JSX_SPREAD_CHILD_RESERVED_BYTES: usize = 8; pub const JSX_SPREAD_CHILD_EXPRESSION_OFFSET: usize = 4; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index 8a5df29939b..d530e4c3198 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -319,7 +319,7 @@ macro_rules! store_import_specifier { macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 12, false); // label $self.update_reference_position(end_position + 4); $self.$label_converter(&$label_value); @@ -335,7 +335,7 @@ macro_rules! store_labeled_statement { macro_rules! store_literal_big_int { ($self:expr, span => $span:expr, bigint => $bigint_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&57u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&58u32.to_ne_bytes(), &$span, 12, false); // bigint $self.convert_string($bigint_value, end_position + 4); // raw @@ -350,7 +350,7 @@ macro_rules! store_literal_boolean { ($self:expr, span => $span:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &58u32.to_ne_bytes(), + &59u32.to_ne_bytes(), &$span, 8, false, @@ -366,7 +366,7 @@ macro_rules! store_literal_boolean { macro_rules! store_literal_null { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&59u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -376,7 +376,7 @@ macro_rules! store_literal_null { macro_rules! store_literal_number { ($self:expr, span => $span:expr, raw => $raw_value:expr, value => $value_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&60u32.to_ne_bytes(), &$span, 16, false); + let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 16, false); // raw if let Some(value) = $raw_value.as_ref() { $self.convert_string(value, end_position + 4); @@ -393,7 +393,7 @@ macro_rules! store_literal_number { macro_rules! store_literal_reg_exp { ($self:expr, span => $span:expr, flags => $flags_value:expr, pattern => $pattern_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&61u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&62u32.to_ne_bytes(), &$span, 12, false); // flags $self.convert_string($flags_value, end_position + 4); // pattern @@ -407,7 +407,7 @@ macro_rules! store_literal_reg_exp { macro_rules! store_literal_string { ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&62u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&63u32.to_ne_bytes(), &$span, 12, false); // value $self.convert_string($value_value, end_position + 4); // raw @@ -423,7 +423,7 @@ macro_rules! store_literal_string { macro_rules! store_object_expression { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&68u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -442,7 +442,7 @@ macro_rules! store_object_expression { macro_rules! store_object_pattern { ($self:expr, span => $span:expr, properties => [$properties_value:expr, $properties_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&69u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&70u32.to_ne_bytes(), &$span, 8, false); // properties $self.convert_item_list( &$properties_value, @@ -461,7 +461,7 @@ macro_rules! store_object_pattern { macro_rules! store_private_identifier { ($self:expr, span => $span:expr, name => $name_value:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&70u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&71u32.to_ne_bytes(), &$span, 8, false); // name $self.convert_string($name_value, end_position + 4); // end @@ -473,7 +473,7 @@ macro_rules! store_private_identifier { macro_rules! store_return_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&75u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 8, false); // argument if let Some(value) = $argument_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -488,7 +488,7 @@ macro_rules! store_return_statement { macro_rules! store_sequence_expression { ($self:expr, span => $span:expr, expressions => [$expressions_value:expr, $expressions_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&76u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&77u32.to_ne_bytes(), &$span, 8, false); // expressions $self.convert_item_list( &$expressions_value, @@ -507,7 +507,7 @@ macro_rules! store_sequence_expression { macro_rules! store_static_block { ($self:expr, span => $span:expr, body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&78u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 8, false); // body $self.convert_item_list(&$body_value, end_position + 4, |ast_converter, node| { ast_converter.$body_converter(node); @@ -522,7 +522,7 @@ macro_rules! store_static_block { macro_rules! store_super_element { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&79u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&80u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -532,7 +532,7 @@ macro_rules! store_super_element { macro_rules! store_switch_case { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], consequent => [$consequent_value:expr, $consequent_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&80u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 12, false); // test if let Some(value) = $test_value.as_ref() { $self.update_reference_position(end_position + 4); @@ -556,7 +556,7 @@ macro_rules! store_switch_case { macro_rules! store_switch_statement { ($self:expr, span => $span:expr, discriminant => [$discriminant_value:expr, $discriminant_converter:ident], cases => [$cases_value:expr, $cases_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&81u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&82u32.to_ne_bytes(), &$span, 12, false); // discriminant $self.update_reference_position(end_position + 4); $self.$discriminant_converter(&$discriminant_value); @@ -574,7 +574,7 @@ macro_rules! store_switch_statement { macro_rules! store_tagged_template_expression { ($self:expr, span => $span:expr, tag => [$tag_value:expr, $tag_converter:ident], quasi => [$quasi_value:expr, $quasi_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&82u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&83u32.to_ne_bytes(), &$span, 12, false); // tag $self.update_reference_position(end_position + 4); $self.$tag_converter(&$tag_value); @@ -591,7 +591,7 @@ macro_rules! store_template_element { ($self:expr, span => $span:expr, tail => $tail_value:expr, cooked => $cooked_value:expr, raw => $raw_value:expr) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &83u32.to_ne_bytes(), + &84u32.to_ne_bytes(), &$span, 16, false, @@ -613,7 +613,7 @@ macro_rules! store_template_element { macro_rules! store_this_expression { ($self:expr, span => $span:expr) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&85u32.to_ne_bytes(), &$span, 4, false); + let end_position = $self.add_type_and_start(&86u32.to_ne_bytes(), &$span, 4, false); // end $self.add_end(end_position, &$span); }; @@ -623,7 +623,7 @@ macro_rules! store_this_expression { macro_rules! store_throw_statement { ($self:expr, span => $span:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&86u32.to_ne_bytes(), &$span, 8, false); + let end_position = $self.add_type_and_start(&87u32.to_ne_bytes(), &$span, 8, false); // argument $self.update_reference_position(end_position + 4); $self.$argument_converter(&$argument_value); @@ -636,7 +636,7 @@ macro_rules! store_throw_statement { macro_rules! store_unary_expression { ($self:expr, span => $span:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&88u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&89u32.to_ne_bytes(), &$span, 12, false); // operator let operator_position = end_position + 4; $self.buffer[operator_position..operator_position + 4].copy_from_slice($operator_value); @@ -653,7 +653,7 @@ macro_rules! store_update_expression { ($self:expr, span => $span:expr, prefix => $prefix_value:expr, operator => $operator_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &89u32.to_ne_bytes(), + &90u32.to_ne_bytes(), &$span, 16, false, @@ -675,7 +675,7 @@ macro_rules! store_update_expression { macro_rules! store_while_statement { ($self:expr, span => $span:expr, test => [$test_value:expr, $test_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { let _: &mut AstConverter = $self; - let end_position = $self.add_type_and_start(&92u32.to_ne_bytes(), &$span, 12, false); + let end_position = $self.add_type_and_start(&93u32.to_ne_bytes(), &$span, 12, false); // test $self.update_reference_position(end_position + 4); $self.$test_converter(&$test_value); @@ -692,7 +692,7 @@ macro_rules! store_yield_expression { ($self:expr, span => $span:expr, delegate => $delegate_value:expr, argument => [$argument_value:expr, $argument_converter:ident]) => { let _: &mut AstConverter = $self; let end_position = $self.add_type_and_start( - &93u32.to_ne_bytes(), + &94u32.to_ne_bytes(), &$span, 12, false, diff --git a/scripts/ast-types.js b/scripts/ast-types.js index 156f0428153..af222ffeb56 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -472,6 +472,11 @@ export const AST_NODES = { estreeType: 'any', useMacro: false }, + JSXSpreadAttribute: { + estreeType: 'any', + fields: [['argument', 'Node']], + useMacro: false + }, JSXSpreadChild: { estreeType: 'any', fields: [['expression', 'Node']], diff --git a/src/ast/bufferParsers.ts b/src/ast/bufferParsers.ts index aae5452a141..0c270c3ff60 100644 --- a/src/ast/bufferParsers.ts +++ b/src/ast/bufferParsers.ts @@ -60,6 +60,7 @@ import JSXMemberExpression from './nodes/JSXMemberExpression'; import JSXNamespacedName from './nodes/JSXNamespacedName'; import JSXOpeningElement from './nodes/JSXOpeningElement'; import JSXOpeningFragment from './nodes/JSXOpeningFragment'; +import JSXSpreadAttribute from './nodes/JSXSpreadAttribute'; import JSXSpreadChild from './nodes/JSXSpreadChild'; import JSXText from './nodes/JSXText'; import LabeledStatement from './nodes/LabeledStatement'; @@ -167,6 +168,7 @@ const nodeTypeStrings = [ 'JSXNamespacedName', 'JSXOpeningElement', 'JSXOpeningFragment', + 'JSXSpreadAttribute', 'JSXSpreadChild', 'JSXText', 'LabeledStatement', @@ -264,6 +266,7 @@ const nodeConstructors: (typeof NodeBase)[] = [ JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, + JSXSpreadAttribute, JSXSpreadChild, JSXText, LabeledStatement, @@ -661,6 +664,10 @@ const bufferParsers: ((node: any, position: number, buffer: AstBuffer) => void)[ node.attributes = []; node.selfClosing = false; }, + function jsxSpreadAttribute(node: JSXSpreadAttribute, position, buffer) { + const { scope } = node; + node.argument = convertNode(node, scope, buffer[position], buffer); + }, function jsxSpreadChild(node: JSXSpreadChild, position, buffer) { const { scope } = node; node.expression = convertNode(node, scope, buffer[position], buffer); diff --git a/src/ast/childNodeKeys.ts b/src/ast/childNodeKeys.ts index fa05838a7c3..2658d723d42 100644 --- a/src/ast/childNodeKeys.ts +++ b/src/ast/childNodeKeys.ts @@ -53,6 +53,7 @@ export const childNodeKeys: Record = { JSXNamespacedName: ['namespace', 'name'], JSXOpeningElement: ['name', 'attributes'], JSXOpeningFragment: [], + JSXSpreadAttribute: ['argument'], JSXSpreadChild: ['expression'], JSXText: [], LabeledStatement: ['label', 'body'], diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index f15e471b99a..bd5bc8b0e42 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -5,13 +5,14 @@ import type JSXAttribute from './JSXAttribute'; import type JSXIdentifier from './JSXIdentifier'; import type JSXMemberExpression from './JSXMemberExpression'; import type JSXNamespacedName from './JSXNamespacedName'; +import JSXSpreadAttribute from './JSXSpreadAttribute'; import type * as NodeType from './NodeType'; import JSXOpeningBase from './shared/JSXOpeningBase'; export default class JSXOpeningElement extends JSXOpeningBase { type!: NodeType.tJSXOpeningElement; name!: JSXIdentifier | JSXMemberExpression | JSXNamespacedName; - attributes!: JSXAttribute /* TODO | JSXSpreadAttribute */[]; + attributes!: (JSXAttribute | JSXSpreadAttribute)[]; selfClosing!: boolean; render(code: MagicString, options: RenderOptions): void { @@ -22,28 +23,70 @@ export default class JSXOpeningElement extends JSXOpeningBase { snippets: { getPropertyAccess }, useOriginalName } = options; + const { + attributes, + end, + factoryVariable, + name: { start: nameStart, end: nameEnd }, + selfClosing, + start + } = this; const [, ...nestedName] = factory.split('.'); code.overwrite( - this.start, - this.name.start, - `/*#__PURE__*/${[this.factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, + start, + nameStart, + `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, { contentOnly: true } ); - if (this.attributes.length > 0) { - code.overwrite(this.name.end, this.attributes[0].start, ', { ', { contentOnly: true }); - for (let index = 0; index < this.attributes.length - 1; index++) { - code.appendLeft(this.attributes[index].end, ', '); + if (attributes.some(attribute => attribute instanceof JSXSpreadAttribute)) { + if (attributes.length === 1) { + code.appendLeft(nameEnd, ','); + code.overwrite(attributes[0].end, end, '', { contentOnly: true }); + } else { + code.appendLeft(nameEnd, ', Object.assign('); + let inObject = false; + if (!(attributes[0] instanceof JSXSpreadAttribute)) { + code.appendLeft(nameEnd, '{'); + inObject = true; + } + for (let index = 1; index < attributes.length; index++) { + const attribute = attributes[index]; + if (attribute instanceof JSXSpreadAttribute) { + if (inObject) { + code.prependRight(attribute.start, '}, '); + inObject = false; + } else { + code.appendLeft(attributes[index - 1].end, ','); + } + } else { + if (inObject) { + code.appendLeft(attributes[index - 1].end, ','); + } else { + code.appendLeft(attributes[index - 1].end, ', {'); + inObject = true; + } + } + } + if (inObject) { + code.appendLeft(attributes.at(-1)!.end, ' }'); + } + code.overwrite(attributes.at(-1)!.end, end, ')', { contentOnly: true }); + } + } else if (attributes.length > 0) { + code.appendLeft(nameEnd, ', {'); + for (let index = 0; index < attributes.length - 1; index++) { + code.appendLeft(attributes[index].end, ', '); } - code.overwrite(this.attributes.at(-1)!.end, this.end, ' }', { + code.overwrite(attributes.at(-1)!.end, end, ' }', { contentOnly: true }); } else { - code.overwrite(this.name.end, this.end, `, null`, { + code.overwrite(nameEnd, end, `, null`, { contentOnly: true }); } - if (this.selfClosing) { - code.appendLeft(this.end, ')'); + if (selfClosing) { + code.appendLeft(end, ')'); } } } diff --git a/src/ast/nodes/JSXSpreadAttribute.ts b/src/ast/nodes/JSXSpreadAttribute.ts new file mode 100644 index 00000000000..7827fde6400 --- /dev/null +++ b/src/ast/nodes/JSXSpreadAttribute.ts @@ -0,0 +1,20 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; +import type { RenderOptions } from '../../utils/renderHelpers'; +import type * as NodeType from './NodeType'; +import type { ExpressionNode } from './shared/Node'; +import { NodeBase } from './shared/Node'; + +export default class JSXSpreadAttribute extends NodeBase { + type!: NodeType.tJSXSpreadAttribute; + argument!: ExpressionNode; + + render(code: MagicString, options: RenderOptions): void { + this.argument.render(code, options); + const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (!preserve) { + code.overwrite(this.start, this.argument.start, '', { contentOnly: true }); + code.overwrite(this.argument.end, this.end, '', { contentOnly: true }); + } + } +} diff --git a/src/ast/nodes/NodeType.ts b/src/ast/nodes/NodeType.ts index f7fae2695a2..65ef0e1a16d 100644 --- a/src/ast/nodes/NodeType.ts +++ b/src/ast/nodes/NodeType.ts @@ -52,6 +52,7 @@ export type tJSXMemberExpression = 'JSXMemberExpression'; export type tJSXNamespacedName = 'JSXNamespacedName'; export type tJSXOpeningElement = 'JSXOpeningElement'; export type tJSXOpeningFragment = 'JSXOpeningFragment'; +export type tJSXSpreadAttribute = 'JSXSpreadAttribute'; export type tJSXSpreadChild = 'JSXSpreadChild'; export type tJSXText = 'JSXText'; export type tLabeledStatement = 'LabeledStatement'; @@ -141,6 +142,7 @@ export const JSXMemberExpression: tJSXMemberExpression = 'JSXMemberExpression'; export const JSXNamespacedName: tJSXNamespacedName = 'JSXNamespacedName'; export const JSXOpeningElement: tJSXOpeningElement = 'JSXOpeningElement'; export const JSXOpeningFragment: tJSXOpeningFragment = 'JSXOpeningFragment'; +export const JSXSpreadAttribute: tJSXSpreadAttribute = 'JSXSpreadAttribute'; export const JSXSpreadChild: tJSXSpreadChild = 'JSXSpreadChild'; export const JSXText: tJSXText = 'JSXText'; export const LabeledStatement: tLabeledStatement = 'LabeledStatement'; diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 1d1d3cc47a7..2ef83573c6c 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -52,6 +52,7 @@ import JSXMemberExpression from './JSXMemberExpression'; import JSXNamespacedName from './JSXNamespacedName'; import JSXOpeningElement from './JSXOpeningElement'; import JSXOpeningFragment from './JSXOpeningFragment'; +import JSXSpreadAttribute from './JSXSpreadAttribute'; import JSXSpreadChild from './JSXSpreadChild'; import JSXText from './JSXText'; import LabeledStatement from './LabeledStatement'; @@ -144,6 +145,7 @@ export const nodeConstructors: Record = { JSXNamespacedName, JSXOpeningElement, JSXOpeningFragment, + JSXSpreadAttribute, JSXSpreadChild, JSXText, LabeledStatement, diff --git a/src/utils/bufferToAst.ts b/src/utils/bufferToAst.ts index 71e6405f2a7..20523a842da 100644 --- a/src/utils/bufferToAst.ts +++ b/src/utils/bufferToAst.ts @@ -558,6 +558,14 @@ const nodeConverters: ((position: number, buffer: AstBuffer) => any)[] = [ selfClosing: false }; }, + function jsxSpreadAttribute(position, buffer): JSXSpreadAttributeNode { + return { + type: 'JSXSpreadAttribute', + start: buffer[position], + end: buffer[position + 1], + argument: convertNode(buffer[position + 2], buffer) + }; + }, function jsxSpreadChild(position, buffer): JSXSpreadChildNode { return { type: 'JSXSpreadChild', @@ -1032,6 +1040,7 @@ export type JSXMemberExpressionNode = RollupAstNode; export type JSXNamespacedNameNode = RollupAstNode; export type JSXOpeningElementNode = RollupAstNode; export type JSXOpeningFragmentNode = RollupAstNode; +export type JSXSpreadAttributeNode = RollupAstNode; export type JSXSpreadChildNode = RollupAstNode; export type JSXTextNode = RollupAstNode; export type LabeledStatementNode = RollupAstNode; diff --git a/test/form/samples/jsx/preserves-jsx-attributes/_expected.js b/test/form/samples/jsx/preserves-jsx-attributes/_expected.js index 490479abe86..652f261869c 100644 --- a/test/form/samples/jsx/preserves-jsx-attributes/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-attributes/_expected.js @@ -10,6 +10,12 @@ const Foo = () => {}; const value = 'value 3'; console.log(Foo, value); -const result = fragment=<> />; +const result = + fragment=<> +/>; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-attributes/main.js b/test/form/samples/jsx/preserves-jsx-attributes/main.js index 3748b4076f4..2297bc014f8 100644 --- a/test/form/samples/jsx/preserves-jsx-attributes/main.js +++ b/test/form/samples/jsx/preserves-jsx-attributes/main.js @@ -2,4 +2,10 @@ import './dep1.js'; import { Foo, value } from './dep2.js'; import './dep3.js'; -export const result = fragment=<> />; +export const result = + fragment=<> +/>; diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js new file mode 100644 index 00000000000..b92dd30971f --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'preserves JSX spread attributes', + options: { + external: ['react'], + jsx: 'preserve' + } +}); diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/_expected.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/_expected.js new file mode 100644 index 00000000000..382aa99a5cf --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/_expected.js @@ -0,0 +1,20 @@ +const obj$2 = { value1: true }; +console.log(obj$2); + +const obj$1 = { value2: true }; +console.log(obj$1); + +const obj = { value3: true }; +console.log(obj); + +const Foo = () => {}; +const result1 = ; +const result2 = ; +const result3 = ; + +export { result1, result2, result3 }; diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/dep1.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/dep1.js new file mode 100644 index 00000000000..658d5636c5a --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/dep1.js @@ -0,0 +1,2 @@ +export const obj = { value1: true }; +console.log(obj); diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/dep2.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/dep2.js new file mode 100644 index 00000000000..bdbe905d08d --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/dep2.js @@ -0,0 +1,2 @@ +export const obj = { value2: true }; +console.log(obj); diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/dep3.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/dep3.js new file mode 100644 index 00000000000..f18273863e3 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/dep3.js @@ -0,0 +1,2 @@ +export const obj = { value3: true }; +console.log(obj); diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/main.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/main.js new file mode 100644 index 00000000000..22953c47609 --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/main.js @@ -0,0 +1,13 @@ +import './dep1.js'; +import { obj } from './dep2.js'; +import './dep3.js'; + +const Foo = () => {}; +export const result1 = ; +export const result2 = ; +export const result3 = ; diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js b/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js index b01053782ee..00859a4c3cb 100644 --- a/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js +++ b/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js @@ -12,6 +12,11 @@ const Foo = () => {}; const value = 'value 3'; console.log(Foo, value); -const result = /*#__PURE__*/react.createElement(Foo$1, { bar: true, "baz:foo": "string", "quux-nix": value$1, element: /*#__PURE__*/react.createElement(Foo$1, null), fragment: /*#__PURE__*/react.createElement(react.Fragment, null) }); +const result = /*#__PURE__*/react.createElement(Foo$1, { + bar: true, + "baz:foo": "string", + "quux-nix": value$1, + element: /*#__PURE__*/react.createElement(Foo$1, null), + fragment: /*#__PURE__*/react.createElement(react.Fragment, null) }); export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/main.js b/test/form/samples/jsx/transpiles-jsx-attributes/main.js index 3748b4076f4..2297bc014f8 100644 --- a/test/form/samples/jsx/transpiles-jsx-attributes/main.js +++ b/test/form/samples/jsx/transpiles-jsx-attributes/main.js @@ -2,4 +2,10 @@ import './dep1.js'; import { Foo, value } from './dep2.js'; import './dep3.js'; -export const result = fragment=<> />; +export const result = + fragment=<> +/>; diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js new file mode 100644 index 00000000000..8301994aa10 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX spread attributes', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_expected.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_expected.js new file mode 100644 index 00000000000..8a83ba54142 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_expected.js @@ -0,0 +1,21 @@ +import react from 'react'; + +const obj$2 = { value1: true }; +console.log(obj$2); + +const obj$1 = { value2: true }; +console.log(obj$1); + +const obj = { value3: true }; +console.log(obj); + +const Foo = () => {}; +const result1 = /*#__PURE__*/react.createElement(Foo, obj$1); +const result2 = /*#__PURE__*/react.createElement(Foo, Object.assign( obj$1, { prop: true })); +const result3 = /*#__PURE__*/react.createElement(Foo, Object.assign({ + prop1: true, + prop2: true + }, obj$1, + obj$1)); + +export { result1, result2, result3 }; diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/dep1.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/dep1.js new file mode 100644 index 00000000000..658d5636c5a --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/dep1.js @@ -0,0 +1,2 @@ +export const obj = { value1: true }; +console.log(obj); diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/dep2.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/dep2.js new file mode 100644 index 00000000000..bdbe905d08d --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/dep2.js @@ -0,0 +1,2 @@ +export const obj = { value2: true }; +console.log(obj); diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/dep3.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/dep3.js new file mode 100644 index 00000000000..f18273863e3 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/dep3.js @@ -0,0 +1,2 @@ +export const obj = { value3: true }; +console.log(obj); diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/main.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/main.js new file mode 100644 index 00000000000..22953c47609 --- /dev/null +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/main.js @@ -0,0 +1,13 @@ +import './dep1.js'; +import { obj } from './dep2.js'; +import './dep3.js'; + +const Foo = () => {}; +export const result1 = ; +export const result2 = ; +export const result3 = ; From b96aa33746a5c04f4960e14b6bdf58097fde632a Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Tue, 21 May 2024 06:50:26 +0200 Subject: [PATCH 30/62] Use correct span for empty expressions --- rust/parse_ast/src/convert_ast/converter.rs | 23 ++++++++++--------- .../_expected.js | 2 +- .../preserves-jsx-empty-expression/main.js | 2 +- .../transpiles-jsx-empty-expression/main.js | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 3ccaf624e82..4211472c1de 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -2,11 +2,11 @@ use swc_common::{Span, Spanned}; use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, - JSXClosingElement, JSXClosingFragment, JSXElement, JSXElementChild, JSXElementName, JSXEmptyExpr, - JSXExpr, JSXExprContainer, JSXFragment, JSXMemberExpr, JSXNamespacedName, JSXObject, - JSXOpeningElement, JSXOpeningFragment, JSXSpreadChild, JSXText, Lit, ModuleDecl, - ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, - PropName, PropOrSpread, SimpleAssignTarget, SpreadElement, Stmt, VarDeclOrExpr, + JSXClosingElement, JSXClosingFragment, JSXElement, JSXElementChild, JSXElementName, JSXExpr, + JSXExprContainer, JSXFragment, JSXMemberExpr, JSXNamespacedName, JSXObject, JSXOpeningElement, + JSXOpeningFragment, JSXSpreadChild, JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, + NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, + SimpleAssignTarget, SpreadElement, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; @@ -839,15 +839,14 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &jsx_element.span); } - fn convert_jsx_empty_expression(&mut self, jsx_empty_expression: &JSXEmptyExpr) { - let end_position = self.add_type_and_start( + fn convert_jsx_empty_expression(&mut self, start: u32, end: u32) { + let end_position = self.add_type_and_explicit_start( &TYPE_JSX_EMPTY_EXPRESSION, - &jsx_empty_expression.span, + start, JSX_EMPTY_EXPRESSION_RESERVED_BYTES, - false, ); // end - self.add_end(end_position, &jsx_empty_expression.span); + self.add_explicit_end(end_position, end); } fn convert_jsx_expression_container(&mut self, jsx_expr_container: &JSXExprContainer) { @@ -864,7 +863,9 @@ impl<'a> AstConverter<'a> { self.convert_expression(expression); } JSXExpr::JSXEmptyExpr(jsx_empty_expr) => { - self.convert_jsx_empty_expression(jsx_empty_expr); + // The span does not consider the size of the container, hence we use the container span + self + .convert_jsx_empty_expression(jsx_expr_container.span.lo.0, jsx_empty_expr.span.hi.0 - 1); } } // end diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js index 406e2404763..f450ad4b610 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_expected.js @@ -1,4 +1,4 @@ const Foo = () => {}; -const result = {}; +const result = {/*Wohoo*/}; export { result }; diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/main.js b/test/form/samples/jsx/preserves-jsx-empty-expression/main.js index cb5632fc2f2..d37a6f1949a 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/main.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/main.js @@ -1,2 +1,2 @@ const Foo = () => {}; -export const result = {}; +export const result = {/*Wohoo*/}; diff --git a/test/form/samples/jsx/transpiles-jsx-empty-expression/main.js b/test/form/samples/jsx/transpiles-jsx-empty-expression/main.js index cb5632fc2f2..d37a6f1949a 100644 --- a/test/form/samples/jsx/transpiles-jsx-empty-expression/main.js +++ b/test/form/samples/jsx/transpiles-jsx-empty-expression/main.js @@ -1,2 +1,2 @@ const Foo = () => {}; -export const result = {}; +export const result = {/*Wohoo*/}; From 22e9bf3f8f4a1e9bc5f508875cdaa534076fa40e Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 2 Aug 2024 10:10:22 +0200 Subject: [PATCH 31/62] Improve formatting for macro names --- rust/parse_ast/src/convert_ast/converter.rs | 4 ++-- rust/parse_ast/src/convert_ast/converter/ast_macros.rs | 2 +- scripts/helpers.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 4211472c1de..87a42411bce 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -43,7 +43,7 @@ use crate::convert_ast::converter::string_constants::{ use crate::convert_ast::converter::utf16_positions::{ ConvertedAnnotation, Utf8ToUtf16ByteIndexConverterAndAnnotationHandler, }; -use crate::store_j_s_x_opening_element_flags; +use crate::store_jsx_opening_element_flags; pub(crate) mod analyze_code; pub mod string_constants; @@ -959,7 +959,7 @@ impl<'a> AstConverter<'a> { false, ); // flags - store_j_s_x_opening_element_flags!( + store_jsx_opening_element_flags!( self, end_position, selfClosing => jsx_opening_element.self_closing diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index d530e4c3198..324ee8294f8 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -775,7 +775,7 @@ macro_rules! store_function_declaration_flags { } #[macro_export] -macro_rules! store_j_s_x_opening_element_flags { +macro_rules! store_jsx_opening_element_flags { ($self:expr, $end_position:expr, selfClosing => $selfClosing_value:expr) => { let _: &mut AstConverter = $self; let _: usize = $end_position; diff --git a/scripts/helpers.js b/scripts/helpers.js index 7b913c4f700..246f975791e 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -114,7 +114,7 @@ export function firstLettersLowercase(string) { * @returns {string} */ export function toSnakeCase(string) { - return string.replace(/(? Date: Fri, 2 Aug 2024 10:39:39 +0200 Subject: [PATCH 32/62] Move converters into separate files --- rust/parse_ast/src/ast_nodes/jsx_attribute.rs | 28 ++ .../src/ast_nodes/jsx_closing_element.rs | 22 ++ .../src/ast_nodes/jsx_closing_fragment.rs | 19 + rust/parse_ast/src/ast_nodes/jsx_element.rs | 37 ++ .../src/ast_nodes/jsx_empty_expression.rs | 16 + .../src/ast_nodes/jsx_expression_container.rs | 31 ++ rust/parse_ast/src/ast_nodes/jsx_fragment.rs | 35 ++ .../parse_ast/src/ast_nodes/jsx_identifier.rs | 21 ++ .../src/ast_nodes/jsx_member_expression.rs | 29 ++ .../src/ast_nodes/jsx_namespaced_name.rs | 29 ++ .../src/ast_nodes/jsx_opening_element.rs | 43 +++ .../src/ast_nodes/jsx_opening_fragment.rs | 19 + .../src/ast_nodes/jsx_spread_attribute.rs | 32 ++ .../src/ast_nodes/jsx_spread_child.rs | 22 ++ rust/parse_ast/src/ast_nodes/jsx_text.rs | 23 ++ rust/parse_ast/src/ast_nodes/mod.rs | 15 + rust/parse_ast/src/convert_ast/converter.rs | 354 ++---------------- 17 files changed, 447 insertions(+), 328 deletions(-) create mode 100644 rust/parse_ast/src/ast_nodes/jsx_attribute.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_closing_element.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_closing_fragment.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_element.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_empty_expression.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_expression_container.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_fragment.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_identifier.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_member_expression.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_namespaced_name.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_opening_element.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_opening_fragment.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_spread_attribute.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_spread_child.rs create mode 100644 rust/parse_ast/src/ast_nodes/jsx_text.rs diff --git a/rust/parse_ast/src/ast_nodes/jsx_attribute.rs b/rust/parse_ast/src/ast_nodes/jsx_attribute.rs new file mode 100644 index 00000000000..25b12c86c34 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_attribute.rs @@ -0,0 +1,28 @@ +use swc_ecma_ast::JSXAttr; + +use crate::convert_ast::converter::ast_constants::{ + JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_ATTRIBUTE_VALUE_OFFSET, + TYPE_JSX_ATTRIBUTE, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_attribute(&mut self, jsx_attribute: &JSXAttr) { + let end_position = self.add_type_and_start( + &TYPE_JSX_ATTRIBUTE, + &jsx_attribute.span, + JSX_ATTRIBUTE_RESERVED_BYTES, + false, + ); + // name + self.update_reference_position(end_position + JSX_ATTRIBUTE_NAME_OFFSET); + self.convert_jsx_attribute_name(&jsx_attribute.name); + // value + if let Some(jsx_attribute_value) = jsx_attribute.value.as_ref() { + self.update_reference_position(end_position + JSX_ATTRIBUTE_VALUE_OFFSET); + self.convert_jsx_attribute_value(jsx_attribute_value); + }; + // end + self.add_end(end_position, &jsx_attribute.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_closing_element.rs b/rust/parse_ast/src/ast_nodes/jsx_closing_element.rs new file mode 100644 index 00000000000..c44c69b8fa8 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_closing_element.rs @@ -0,0 +1,22 @@ +use swc_ecma_ast::JSXClosingElement; + +use crate::convert_ast::converter::ast_constants::{ + JSX_CLOSING_ELEMENT_NAME_OFFSET, JSX_CLOSING_ELEMENT_RESERVED_BYTES, TYPE_JSX_CLOSING_ELEMENT, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_closing_element(&mut self, jsx_closing_element: &JSXClosingElement) { + let end_position = self.add_type_and_start( + &TYPE_JSX_CLOSING_ELEMENT, + &jsx_closing_element.span, + JSX_CLOSING_ELEMENT_RESERVED_BYTES, + false, + ); + // name + self.update_reference_position(end_position + JSX_CLOSING_ELEMENT_NAME_OFFSET); + self.convert_jsx_element_name(&jsx_closing_element.name); + // end + self.add_end(end_position, &jsx_closing_element.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_closing_fragment.rs b/rust/parse_ast/src/ast_nodes/jsx_closing_fragment.rs new file mode 100644 index 00000000000..4c93b063852 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_closing_fragment.rs @@ -0,0 +1,19 @@ +use swc_ecma_ast::JSXClosingFragment; + +use crate::convert_ast::converter::ast_constants::{ + JSX_CLOSING_FRAGMENT_RESERVED_BYTES, TYPE_JSX_CLOSING_FRAGMENT, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_closing_fragment(&mut self, jsx_closing_fragment: &JSXClosingFragment) { + let end_position = self.add_type_and_start( + &TYPE_JSX_CLOSING_FRAGMENT, + &jsx_closing_fragment.span, + JSX_CLOSING_FRAGMENT_RESERVED_BYTES, + false, + ); + // end + self.add_end(end_position, &jsx_closing_fragment.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_element.rs b/rust/parse_ast/src/ast_nodes/jsx_element.rs new file mode 100644 index 00000000000..79c1912ab90 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_element.rs @@ -0,0 +1,37 @@ +use swc_ecma_ast::JSXElement; + +use crate::convert_ast::converter::ast_constants::{ + JSX_ELEMENT_CHILDREN_OFFSET, JSX_ELEMENT_CLOSING_ELEMENT_OFFSET, + JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, TYPE_JSX_ELEMENT, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_element(&mut self, jsx_element: &JSXElement) { + let end_position = self.add_type_and_start( + &TYPE_JSX_ELEMENT, + &jsx_element.span, + JSX_ELEMENT_RESERVED_BYTES, + false, + ); + // openingElement + self.update_reference_position(end_position + JSX_ELEMENT_OPENING_ELEMENT_OFFSET); + self.store_jsx_opening_element(&jsx_element.opening); + // children + self.convert_item_list( + &jsx_element.children, + end_position + JSX_ELEMENT_CHILDREN_OFFSET, + |ast_converter, jsx_element_child| { + ast_converter.convert_jsx_element_child(jsx_element_child); + true + }, + ); + // closingElement + if let Some(closing) = jsx_element.closing.as_ref() { + self.update_reference_position(end_position + JSX_ELEMENT_CLOSING_ELEMENT_OFFSET); + self.store_jsx_closing_element(closing); + } + // end + self.add_end(end_position, &jsx_element.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_empty_expression.rs b/rust/parse_ast/src/ast_nodes/jsx_empty_expression.rs new file mode 100644 index 00000000000..c0b80dd582a --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_empty_expression.rs @@ -0,0 +1,16 @@ +use crate::convert_ast::converter::ast_constants::{ + JSX_EMPTY_EXPRESSION_RESERVED_BYTES, TYPE_JSX_EMPTY_EXPRESSION, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_empty_expression(&mut self, start: u32, end: u32) { + let end_position = self.add_type_and_explicit_start( + &TYPE_JSX_EMPTY_EXPRESSION, + start, + JSX_EMPTY_EXPRESSION_RESERVED_BYTES, + ); + // end + self.add_explicit_end(end_position, end); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_expression_container.rs b/rust/parse_ast/src/ast_nodes/jsx_expression_container.rs new file mode 100644 index 00000000000..d1dc186e0d2 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_expression_container.rs @@ -0,0 +1,31 @@ +use swc_ecma_ast::{JSXExpr, JSXExprContainer}; + +use crate::convert_ast::converter::ast_constants::{ + JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET, JSX_EXPRESSION_CONTAINER_RESERVED_BYTES, + TYPE_JSX_EXPRESSION_CONTAINER, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_expression_container(&mut self, jsx_expr_container: &JSXExprContainer) { + let end_position = self.add_type_and_start( + &TYPE_JSX_EXPRESSION_CONTAINER, + &jsx_expr_container.span, + JSX_EXPRESSION_CONTAINER_RESERVED_BYTES, + false, + ); + // expression + self.update_reference_position(end_position + JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET); + match &jsx_expr_container.expr { + JSXExpr::Expr(expression) => { + self.convert_expression(expression); + } + JSXExpr::JSXEmptyExpr(jsx_empty_expr) => { + // The span does not consider the size of the container, hence we use the container span + self.store_jsx_empty_expression(jsx_expr_container.span.lo.0, jsx_empty_expr.span.hi.0 - 1); + } + } + // end + self.add_end(end_position, &jsx_expr_container.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_fragment.rs b/rust/parse_ast/src/ast_nodes/jsx_fragment.rs new file mode 100644 index 00000000000..8809ed43b29 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_fragment.rs @@ -0,0 +1,35 @@ +use swc_ecma_ast::JSXFragment; + +use crate::convert_ast::converter::ast_constants::{ + JSX_FRAGMENT_CHILDREN_OFFSET, JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET, + JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET, JSX_FRAGMENT_RESERVED_BYTES, TYPE_JSX_FRAGMENT, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_fragment(&mut self, jsx_fragment: &JSXFragment) { + let end_position = self.add_type_and_start( + &TYPE_JSX_FRAGMENT, + &jsx_fragment.span, + JSX_FRAGMENT_RESERVED_BYTES, + false, + ); + // openingFragment + self.update_reference_position(end_position + JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET); + self.store_jsx_opening_fragment(jsx_fragment.opening); + // children + self.convert_item_list( + &jsx_fragment.children, + end_position + JSX_FRAGMENT_CHILDREN_OFFSET, + |ast_converter, jsx_element_child| { + ast_converter.convert_jsx_element_child(jsx_element_child); + true + }, + ); + // closingFragment + self.update_reference_position(end_position + JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET); + self.store_jsx_closing_fragment(&jsx_fragment.closing); + // end + self.add_end(end_position, &jsx_fragment.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_identifier.rs b/rust/parse_ast/src/ast_nodes/jsx_identifier.rs new file mode 100644 index 00000000000..92e941b0d1e --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_identifier.rs @@ -0,0 +1,21 @@ +use swc_common::Span; + +use crate::convert_ast::converter::ast_constants::{ + JSX_IDENTIFIER_NAME_OFFSET, JSX_IDENTIFIER_RESERVED_BYTES, TYPE_JSX_IDENTIFIER, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_identifier(&mut self, span: &Span, name: &str) { + let end_position = self.add_type_and_start( + &TYPE_JSX_IDENTIFIER, + span, + JSX_IDENTIFIER_RESERVED_BYTES, + false, + ); + // name + self.convert_string(name, end_position + JSX_IDENTIFIER_NAME_OFFSET); + // end + self.add_end(end_position, span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_member_expression.rs b/rust/parse_ast/src/ast_nodes/jsx_member_expression.rs new file mode 100644 index 00000000000..bb006ef2687 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_member_expression.rs @@ -0,0 +1,29 @@ +use swc_ecma_ast::JSXMemberExpr; + +use crate::convert_ast::converter::ast_constants::{ + JSX_MEMBER_EXPRESSION_OBJECT_OFFSET, JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET, + JSX_MEMBER_EXPRESSION_RESERVED_BYTES, TYPE_JSX_MEMBER_EXPRESSION, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_member_expression(&mut self, jsx_member_expression: &JSXMemberExpr) { + let end_position = self.add_type_and_start( + &TYPE_JSX_MEMBER_EXPRESSION, + &jsx_member_expression.span, + JSX_MEMBER_EXPRESSION_RESERVED_BYTES, + false, + ); + // object + self.update_reference_position(end_position + JSX_MEMBER_EXPRESSION_OBJECT_OFFSET); + self.convert_jsx_object(&jsx_member_expression.obj); + // property + self.update_reference_position(end_position + JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET); + self.store_jsx_identifier( + &jsx_member_expression.prop.span, + &jsx_member_expression.prop.sym, + ); + // end + self.add_end(end_position, &jsx_member_expression.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_namespaced_name.rs b/rust/parse_ast/src/ast_nodes/jsx_namespaced_name.rs new file mode 100644 index 00000000000..6a81c53cd2c --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_namespaced_name.rs @@ -0,0 +1,29 @@ +use swc_ecma_ast::JSXNamespacedName; + +use crate::convert_ast::converter::ast_constants::{ + JSX_NAMESPACED_NAME_NAME_OFFSET, JSX_NAMESPACED_NAME_NAMESPACE_OFFSET, + JSX_NAMESPACED_NAME_RESERVED_BYTES, TYPE_JSX_NAMESPACED_NAME, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_namespaced_name(&mut self, jsx_namespaced_name: &JSXNamespacedName) { + let end_position = self.add_type_and_start( + &TYPE_JSX_NAMESPACED_NAME, + &jsx_namespaced_name.ns.span, + JSX_NAMESPACED_NAME_RESERVED_BYTES, + false, + ); + // namespace + self.update_reference_position(end_position + JSX_NAMESPACED_NAME_NAMESPACE_OFFSET); + self.store_jsx_identifier(&jsx_namespaced_name.ns.span, &jsx_namespaced_name.ns.sym); + // name + self.update_reference_position(end_position + JSX_NAMESPACED_NAME_NAME_OFFSET); + self.store_jsx_identifier( + &jsx_namespaced_name.name.span, + &jsx_namespaced_name.name.sym, + ); + // end + self.add_end(end_position, &jsx_namespaced_name.name.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_opening_element.rs b/rust/parse_ast/src/ast_nodes/jsx_opening_element.rs new file mode 100644 index 00000000000..c7d0e0b32ed --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_opening_element.rs @@ -0,0 +1,43 @@ +use swc_common::Spanned; +use swc_ecma_ast::JSXOpeningElement; + +use crate::convert_ast::converter::ast_constants::{ + JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, + JSX_OPENING_ELEMENT_RESERVED_BYTES, TYPE_JSX_OPENING_ELEMENT, +}; +use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_opening_element_flags; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_opening_element(&mut self, jsx_opening_element: &JSXOpeningElement) { + let end_position = self.add_type_and_start( + &TYPE_JSX_OPENING_ELEMENT, + &jsx_opening_element.span, + JSX_OPENING_ELEMENT_RESERVED_BYTES, + false, + ); + // flags + store_jsx_opening_element_flags!( + self, + end_position, + selfClosing => jsx_opening_element.self_closing + ); + // name + self.update_reference_position(end_position + JSX_OPENING_ELEMENT_NAME_OFFSET); + self.convert_jsx_element_name(&jsx_opening_element.name); + // attributes + let mut previous_element_end = jsx_opening_element.name.span().hi.0; + self.convert_item_list_with_state( + &jsx_opening_element.attrs, + &mut previous_element_end, + end_position + JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, + |ast_converter, jsx_attribute, previous_end| { + ast_converter.convert_jsx_attribute_or_spread(jsx_attribute, *previous_end); + *previous_end = jsx_attribute.span().hi.0; + true + }, + ); + // end + self.add_end(end_position, &jsx_opening_element.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_opening_fragment.rs b/rust/parse_ast/src/ast_nodes/jsx_opening_fragment.rs new file mode 100644 index 00000000000..5ec19e624c8 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_opening_fragment.rs @@ -0,0 +1,19 @@ +use swc_ecma_ast::JSXOpeningFragment; + +use crate::convert_ast::converter::ast_constants::{ + JSX_OPENING_FRAGMENT_RESERVED_BYTES, TYPE_JSX_OPENING_FRAGMENT, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_opening_fragment(&mut self, jsxopening_fragment: JSXOpeningFragment) { + let end_position = self.add_type_and_start( + &TYPE_JSX_OPENING_FRAGMENT, + &jsxopening_fragment.span, + JSX_OPENING_FRAGMENT_RESERVED_BYTES, + false, + ); + // end + self.add_end(end_position, &jsxopening_fragment.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_spread_attribute.rs b/rust/parse_ast/src/ast_nodes/jsx_spread_attribute.rs new file mode 100644 index 00000000000..86eb4dfcd96 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_spread_attribute.rs @@ -0,0 +1,32 @@ +use swc_common::Spanned; +use swc_ecma_ast::SpreadElement; + +use crate::convert_ast::converter::analyze_code::find_first_occurrence_outside_comment; +use crate::convert_ast::converter::ast_constants::{ + JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET, JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES, + TYPE_JSX_SPREAD_ATTRIBUTE, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_spread_attribute( + &mut self, + spread_element: &SpreadElement, + previous_element_end: u32, + ) { + let end_position = self.add_type_and_explicit_start( + &TYPE_JSX_SPREAD_ATTRIBUTE, + find_first_occurrence_outside_comment(self.code, b'{', previous_element_end), + JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES, + ); + // argument + self.update_reference_position(end_position + JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET); + self.convert_expression(&spread_element.expr); + // end + self.add_explicit_end( + end_position, + find_first_occurrence_outside_comment(self.code, b'}', spread_element.expr.span().hi.0 - 1) + + 1, + ); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_spread_child.rs b/rust/parse_ast/src/ast_nodes/jsx_spread_child.rs new file mode 100644 index 00000000000..3b1c4ac795a --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_spread_child.rs @@ -0,0 +1,22 @@ +use swc_ecma_ast::JSXSpreadChild; + +use crate::convert_ast::converter::ast_constants::{ + JSX_SPREAD_CHILD_EXPRESSION_OFFSET, JSX_SPREAD_CHILD_RESERVED_BYTES, TYPE_JSX_SPREAD_CHILD, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_spread_child(&mut self, jsx_spread_child: &JSXSpreadChild) { + let end_position = self.add_type_and_start( + &TYPE_JSX_SPREAD_CHILD, + &jsx_spread_child.span, + JSX_SPREAD_CHILD_RESERVED_BYTES, + false, + ); + // expression + self.update_reference_position(end_position + JSX_SPREAD_CHILD_EXPRESSION_OFFSET); + self.convert_expression(&jsx_spread_child.expr); + // end + self.add_end(end_position, &jsx_spread_child.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/jsx_text.rs b/rust/parse_ast/src/ast_nodes/jsx_text.rs new file mode 100644 index 00000000000..0d8d69e82d1 --- /dev/null +++ b/rust/parse_ast/src/ast_nodes/jsx_text.rs @@ -0,0 +1,23 @@ +use swc_ecma_ast::JSXText; + +use crate::convert_ast::converter::ast_constants::{ + JSX_TEXT_RAW_OFFSET, JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_JSX_TEXT, +}; +use crate::convert_ast::converter::AstConverter; + +impl<'a> AstConverter<'a> { + pub(crate) fn store_jsx_text(&mut self, jsx_text: &JSXText) { + let end_position = self.add_type_and_start( + &TYPE_JSX_TEXT, + &jsx_text.span, + JSX_TEXT_RESERVED_BYTES, + false, + ); + // value + self.convert_string(&jsx_text.value, end_position + JSX_TEXT_VALUE_OFFSET); + // raw + self.convert_string(&jsx_text.raw, end_position + JSX_TEXT_RAW_OFFSET); + // end + self.add_end(end_position, &jsx_text.span); + } +} diff --git a/rust/parse_ast/src/ast_nodes/mod.rs b/rust/parse_ast/src/ast_nodes/mod.rs index 2284cc3e01b..6460225cc11 100644 --- a/rust/parse_ast/src/ast_nodes/mod.rs +++ b/rust/parse_ast/src/ast_nodes/mod.rs @@ -38,6 +38,21 @@ pub mod import_default_specifier; pub mod import_expression; pub mod import_namespace_specifier; pub mod import_specifier; +pub mod jsx_attribute; +pub mod jsx_closing_element; +pub mod jsx_closing_fragment; +pub mod jsx_element; +pub mod jsx_empty_expression; +pub mod jsx_expression_container; +pub mod jsx_fragment; +pub mod jsx_identifier; +pub mod jsx_member_expression; +pub mod jsx_namespaced_name; +pub mod jsx_opening_element; +pub mod jsx_opening_fragment; +pub mod jsx_spread_attribute; +pub mod jsx_spread_child; +pub mod jsx_text; pub mod labeled_statement; pub mod literal_big_int; pub mod literal_boolean; diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 87a42411bce..bd773bb0c38 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,41 +1,17 @@ -use swc_common::{Span, Spanned}; +use swc_common::Span; use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, - ExprOrSpread, ForHead, ImportSpecifier, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, - JSXClosingElement, JSXClosingFragment, JSXElement, JSXElementChild, JSXElementName, JSXExpr, - JSXExprContainer, JSXFragment, JSXMemberExpr, JSXNamespacedName, JSXObject, JSXOpeningElement, - JSXOpeningFragment, JSXSpreadChild, JSXText, Lit, ModuleDecl, ModuleExportName, ModuleItem, + ExprOrSpread, ForHead, ImportSpecifier, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, + JSXElementChild, JSXElementName, JSXObject, Lit, ModuleDecl, ModuleExportName, ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, - SimpleAssignTarget, SpreadElement, Stmt, VarDeclOrExpr, + SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; use crate::ast_nodes::variable_declaration::VariableDeclaration; use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; -use crate::convert_ast::converter::analyze_code::find_first_occurrence_outside_comment; use crate::convert_ast::converter::ast_constants::{ - JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_ATTRIBUTE_VALUE_OFFSET, - JSX_CLOSING_ELEMENT_NAME_OFFSET, JSX_CLOSING_ELEMENT_RESERVED_BYTES, - JSX_CLOSING_FRAGMENT_RESERVED_BYTES, JSX_ELEMENT_CHILDREN_OFFSET, - JSX_ELEMENT_CLOSING_ELEMENT_OFFSET, JSX_ELEMENT_OPENING_ELEMENT_OFFSET, - JSX_ELEMENT_RESERVED_BYTES, JSX_EMPTY_EXPRESSION_RESERVED_BYTES, - JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET, JSX_EXPRESSION_CONTAINER_RESERVED_BYTES, - JSX_FRAGMENT_CHILDREN_OFFSET, JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET, - JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET, JSX_FRAGMENT_RESERVED_BYTES, JSX_IDENTIFIER_NAME_OFFSET, - JSX_IDENTIFIER_RESERVED_BYTES, JSX_MEMBER_EXPRESSION_OBJECT_OFFSET, - JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET, JSX_MEMBER_EXPRESSION_RESERVED_BYTES, - JSX_NAMESPACED_NAME_NAME_OFFSET, JSX_NAMESPACED_NAME_NAMESPACE_OFFSET, - JSX_NAMESPACED_NAME_RESERVED_BYTES, JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, - JSX_OPENING_ELEMENT_NAME_OFFSET, JSX_OPENING_ELEMENT_RESERVED_BYTES, - JSX_OPENING_FRAGMENT_RESERVED_BYTES, JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET, - JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES, JSX_SPREAD_CHILD_EXPRESSION_OFFSET, - JSX_SPREAD_CHILD_RESERVED_BYTES, JSX_TEXT_RAW_OFFSET, JSX_TEXT_RESERVED_BYTES, - JSX_TEXT_VALUE_OFFSET, TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, - TYPE_FUNCTION_EXPRESSION, TYPE_JSX_ATTRIBUTE, TYPE_JSX_CLOSING_ELEMENT, - TYPE_JSX_CLOSING_FRAGMENT, TYPE_JSX_ELEMENT, TYPE_JSX_EMPTY_EXPRESSION, - TYPE_JSX_EXPRESSION_CONTAINER, TYPE_JSX_FRAGMENT, TYPE_JSX_IDENTIFIER, - TYPE_JSX_MEMBER_EXPRESSION, TYPE_JSX_NAMESPACED_NAME, TYPE_JSX_OPENING_ELEMENT, - TYPE_JSX_OPENING_FRAGMENT, TYPE_JSX_SPREAD_ATTRIBUTE, TYPE_JSX_SPREAD_CHILD, TYPE_JSX_TEXT, + TYPE_CLASS_EXPRESSION, TYPE_FUNCTION_DECLARATION, TYPE_FUNCTION_EXPRESSION, }; use crate::convert_ast::converter::string_constants::{ STRING_NOSIDEEFFECTS, STRING_PURE, STRING_SOURCEMAP, @@ -43,7 +19,6 @@ use crate::convert_ast::converter::string_constants::{ use crate::convert_ast::converter::utf16_positions::{ ConvertedAnnotation, Utf8ToUtf16ByteIndexConverterAndAnnotationHandler, }; -use crate::store_jsx_opening_element_flags; pub(crate) mod analyze_code; pub mod string_constants; @@ -389,10 +364,10 @@ impl<'a> AstConverter<'a> { Expr::JSXNamespacedName(_) => unimplemented!("Cannot convert Expr::JSXNamespacedName"), Expr::JSXEmpty(_) => unimplemented!("Cannot convert Expr::JSXEmpty"), Expr::JSXElement(jsx_element) => { - self.convert_jsx_element(jsx_element); + self.store_jsx_element(jsx_element); } Expr::JSXFragment(jsx_fragment) => { - self.convert_jsx_fragment(jsx_fragment); + self.store_jsx_fragment(jsx_fragment); } Expr::TsTypeAssertion(_) => unimplemented!("Cannot convert Expr::TsTypeAssertion"), Expr::TsConstAssertion(_) => unimplemented!("Cannot convert Expr::TsConstAssertion"), @@ -441,70 +416,70 @@ impl<'a> AstConverter<'a> { } } - fn convert_jsx_attribute_name(&mut self, jsx_attribute_name: &JSXAttrName) { + pub(crate) fn convert_jsx_attribute_name(&mut self, jsx_attribute_name: &JSXAttrName) { match jsx_attribute_name { JSXAttrName::Ident(identifier) => { self.store_jsx_identifier(&identifier.span, &identifier.sym); } JSXAttrName::JSXNamespacedName(jsx_namespaced_name) => { - self.convert_jsx_namespaced_name(jsx_namespaced_name); + self.store_jsx_namespaced_name(jsx_namespaced_name); } } } - fn convert_jsx_attribute_or_spread( + pub(crate) fn convert_jsx_attribute_or_spread( &mut self, jsx_attribute_or_spread: &JSXAttrOrSpread, previous_element_end: u32, ) { match jsx_attribute_or_spread { JSXAttrOrSpread::JSXAttr(jsx_attribute) => { - self.convert_jsx_attribute(jsx_attribute); + self.store_jsx_attribute(jsx_attribute); } JSXAttrOrSpread::SpreadElement(spread_element) => { - self.convert_jsx_spread_element(spread_element, previous_element_end); + self.store_jsx_spread_attribute(spread_element, previous_element_end); } } } - fn convert_jsx_attribute_value(&mut self, jsx_attribute_value: &JSXAttrValue) { + pub(crate) fn convert_jsx_attribute_value(&mut self, jsx_attribute_value: &JSXAttrValue) { match jsx_attribute_value { JSXAttrValue::Lit(literal) => self.convert_literal(literal), JSXAttrValue::JSXExprContainer(expression_container) => { - self.convert_jsx_expression_container(expression_container) + self.store_jsx_expression_container(expression_container) } - JSXAttrValue::JSXElement(jsx_element) => self.convert_jsx_element(jsx_element), - JSXAttrValue::JSXFragment(jsx_fragment) => self.convert_jsx_fragment(jsx_fragment), + JSXAttrValue::JSXElement(jsx_element) => self.store_jsx_element(jsx_element), + JSXAttrValue::JSXFragment(jsx_fragment) => self.store_jsx_fragment(jsx_fragment), } } - fn convert_jsx_element_child(&mut self, jsx_element_child: &JSXElementChild) { + pub(crate) fn convert_jsx_element_child(&mut self, jsx_element_child: &JSXElementChild) { match jsx_element_child { JSXElementChild::JSXText(jsx_text) => { - self.convert_jsx_text(jsx_text); + self.store_jsx_text(jsx_text); } JSXElementChild::JSXExprContainer(jsx_expr_container) => { - self.convert_jsx_expression_container(jsx_expr_container); + self.store_jsx_expression_container(jsx_expr_container); } JSXElementChild::JSXSpreadChild(jsx_spread_child) => { - self.convert_jsx_spread_child(jsx_spread_child); + self.store_jsx_spread_child(jsx_spread_child); } JSXElementChild::JSXFragment(jsx_fragment) => { - self.convert_jsx_fragment(jsx_fragment); + self.store_jsx_fragment(jsx_fragment); } JSXElementChild::JSXElement(jsx_element) => { - self.convert_jsx_element(jsx_element); + self.store_jsx_element(jsx_element); } } } - fn convert_jsx_element_name(&mut self, jsx_element_name: &JSXElementName) { + pub(crate) fn convert_jsx_element_name(&mut self, jsx_element_name: &JSXElementName) { match jsx_element_name { JSXElementName::Ident(identifier) => { self.store_jsx_identifier(&identifier.span, &identifier.sym) } JSXElementName::JSXMemberExpr(jsx_member_expression) => { - self.convert_jsx_member_expression(jsx_member_expression); + self.store_jsx_member_expression(jsx_member_expression); } JSXElementName::JSXNamespacedName(_jsx_namespaced_name) => { unimplemented!("JSXElementName::JSXNamespacedName") @@ -512,10 +487,10 @@ impl<'a> AstConverter<'a> { } } - fn convert_jsx_object(&mut self, jsx_object: &JSXObject) { + pub(crate) fn convert_jsx_object(&mut self, jsx_object: &JSXObject) { match jsx_object { JSXObject::JSXMemberExpr(jsx_member_expression) => { - self.convert_jsx_member_expression(jsx_member_expression); + self.store_jsx_member_expression(jsx_member_expression); } JSXObject::Ident(identifier) => { self.store_jsx_identifier(&identifier.span, &identifier.sym); @@ -766,283 +741,6 @@ impl<'a> AstConverter<'a> { } } } - - fn convert_jsx_attribute(&mut self, jsx_attribute: &JSXAttr) { - let end_position = self.add_type_and_start( - &TYPE_JSX_ATTRIBUTE, - &jsx_attribute.span, - JSX_ATTRIBUTE_RESERVED_BYTES, - false, - ); - // name - self.update_reference_position(end_position + JSX_ATTRIBUTE_NAME_OFFSET); - self.convert_jsx_attribute_name(&jsx_attribute.name); - // value - if let Some(jsx_attribute_value) = jsx_attribute.value.as_ref() { - self.update_reference_position(end_position + JSX_ATTRIBUTE_VALUE_OFFSET); - self.convert_jsx_attribute_value(jsx_attribute_value); - }; - // end - self.add_end(end_position, &jsx_attribute.span); - } - - fn convert_jsx_closing_element(&mut self, jsx_closing_element: &JSXClosingElement) { - let end_position = self.add_type_and_start( - &TYPE_JSX_CLOSING_ELEMENT, - &jsx_closing_element.span, - JSX_CLOSING_ELEMENT_RESERVED_BYTES, - false, - ); - // name - self.update_reference_position(end_position + JSX_CLOSING_ELEMENT_NAME_OFFSET); - self.convert_jsx_element_name(&jsx_closing_element.name); - // end - self.add_end(end_position, &jsx_closing_element.span); - } - - fn convert_jsx_closing_fragment(&mut self, jsx_closing_fragment: &JSXClosingFragment) { - let end_position = self.add_type_and_start( - &TYPE_JSX_CLOSING_FRAGMENT, - &jsx_closing_fragment.span, - JSX_CLOSING_FRAGMENT_RESERVED_BYTES, - false, - ); - // end - self.add_end(end_position, &jsx_closing_fragment.span); - } - - fn convert_jsx_element(&mut self, jsx_element: &JSXElement) { - let end_position = self.add_type_and_start( - &TYPE_JSX_ELEMENT, - &jsx_element.span, - JSX_ELEMENT_RESERVED_BYTES, - false, - ); - // openingElement - self.update_reference_position(end_position + JSX_ELEMENT_OPENING_ELEMENT_OFFSET); - self.convert_jsx_opening_element(&jsx_element.opening); - // children - self.convert_item_list( - &jsx_element.children, - end_position + JSX_ELEMENT_CHILDREN_OFFSET, - |ast_converter, jsx_element_child| { - ast_converter.convert_jsx_element_child(jsx_element_child); - true - }, - ); - // closingElement - if let Some(closing) = jsx_element.closing.as_ref() { - self.update_reference_position(end_position + JSX_ELEMENT_CLOSING_ELEMENT_OFFSET); - self.convert_jsx_closing_element(closing); - } - // end - self.add_end(end_position, &jsx_element.span); - } - - fn convert_jsx_empty_expression(&mut self, start: u32, end: u32) { - let end_position = self.add_type_and_explicit_start( - &TYPE_JSX_EMPTY_EXPRESSION, - start, - JSX_EMPTY_EXPRESSION_RESERVED_BYTES, - ); - // end - self.add_explicit_end(end_position, end); - } - - fn convert_jsx_expression_container(&mut self, jsx_expr_container: &JSXExprContainer) { - let end_position = self.add_type_and_start( - &TYPE_JSX_EXPRESSION_CONTAINER, - &jsx_expr_container.span, - JSX_EXPRESSION_CONTAINER_RESERVED_BYTES, - false, - ); - // expression - self.update_reference_position(end_position + JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET); - match &jsx_expr_container.expr { - JSXExpr::Expr(expression) => { - self.convert_expression(expression); - } - JSXExpr::JSXEmptyExpr(jsx_empty_expr) => { - // The span does not consider the size of the container, hence we use the container span - self - .convert_jsx_empty_expression(jsx_expr_container.span.lo.0, jsx_empty_expr.span.hi.0 - 1); - } - } - // end - self.add_end(end_position, &jsx_expr_container.span); - } - - fn convert_jsx_fragment(&mut self, jsx_fragment: &JSXFragment) { - let end_position = self.add_type_and_start( - &TYPE_JSX_FRAGMENT, - &jsx_fragment.span, - JSX_FRAGMENT_RESERVED_BYTES, - false, - ); - // openingFragment - self.update_reference_position(end_position + JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET); - self.convert_jsx_opening_fragment(jsx_fragment.opening); - // children - self.convert_item_list( - &jsx_fragment.children, - end_position + JSX_FRAGMENT_CHILDREN_OFFSET, - |ast_converter, jsx_element_child| { - ast_converter.convert_jsx_element_child(jsx_element_child); - true - }, - ); - // closingFragment - self.update_reference_position(end_position + JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET); - self.convert_jsx_closing_fragment(&jsx_fragment.closing); - // end - self.add_end(end_position, &jsx_fragment.span); - } - - fn store_jsx_identifier(&mut self, span: &Span, name: &str) { - let end_position = self.add_type_and_start( - &TYPE_JSX_IDENTIFIER, - span, - JSX_IDENTIFIER_RESERVED_BYTES, - false, - ); - // name - self.convert_string(name, end_position + JSX_IDENTIFIER_NAME_OFFSET); - // end - self.add_end(end_position, span); - } - - fn convert_jsx_member_expression(&mut self, jsx_member_expression: &JSXMemberExpr) { - let end_position = self.add_type_and_start( - &TYPE_JSX_MEMBER_EXPRESSION, - &jsx_member_expression.span, - JSX_MEMBER_EXPRESSION_RESERVED_BYTES, - false, - ); - // object - self.update_reference_position(end_position + JSX_MEMBER_EXPRESSION_OBJECT_OFFSET); - self.convert_jsx_object(&jsx_member_expression.obj); - // property - self.update_reference_position(end_position + JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET); - self.store_jsx_identifier( - &jsx_member_expression.prop.span, - &jsx_member_expression.prop.sym, - ); - // end - self.add_end(end_position, &jsx_member_expression.span); - } - - fn convert_jsx_namespaced_name(&mut self, jsx_namespaced_name: &JSXNamespacedName) { - let end_position = self.add_type_and_start( - &TYPE_JSX_NAMESPACED_NAME, - &jsx_namespaced_name.ns.span, - JSX_NAMESPACED_NAME_RESERVED_BYTES, - false, - ); - // namespace - self.update_reference_position(end_position + JSX_NAMESPACED_NAME_NAMESPACE_OFFSET); - self.store_jsx_identifier(&jsx_namespaced_name.ns.span, &jsx_namespaced_name.ns.sym); - // name - self.update_reference_position(end_position + JSX_NAMESPACED_NAME_NAME_OFFSET); - self.store_jsx_identifier( - &jsx_namespaced_name.name.span, - &jsx_namespaced_name.name.sym, - ); - // end - self.add_end(end_position, &jsx_namespaced_name.name.span); - } - - fn convert_jsx_opening_element(&mut self, jsx_opening_element: &JSXOpeningElement) { - let end_position = self.add_type_and_start( - &TYPE_JSX_OPENING_ELEMENT, - &jsx_opening_element.span, - JSX_OPENING_ELEMENT_RESERVED_BYTES, - false, - ); - // flags - store_jsx_opening_element_flags!( - self, - end_position, - selfClosing => jsx_opening_element.self_closing - ); - // name - self.update_reference_position(end_position + JSX_OPENING_ELEMENT_NAME_OFFSET); - self.convert_jsx_element_name(&jsx_opening_element.name); - // attributes - let mut previous_element_end = jsx_opening_element.name.span().hi.0; - self.convert_item_list_with_state( - &jsx_opening_element.attrs, - &mut previous_element_end, - end_position + JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, - |ast_converter, jsx_attribute, previous_end| { - ast_converter.convert_jsx_attribute_or_spread(jsx_attribute, *previous_end); - *previous_end = jsx_attribute.span().hi.0; - true - }, - ); - // end - self.add_end(end_position, &jsx_opening_element.span); - } - - fn convert_jsx_opening_fragment(&mut self, jsxopening_fragment: JSXOpeningFragment) { - let end_position = self.add_type_and_start( - &TYPE_JSX_OPENING_FRAGMENT, - &jsxopening_fragment.span, - JSX_OPENING_FRAGMENT_RESERVED_BYTES, - false, - ); - // end - self.add_end(end_position, &jsxopening_fragment.span); - } - - fn convert_jsx_spread_child(&mut self, jsx_spread_child: &JSXSpreadChild) { - let end_position = self.add_type_and_start( - &TYPE_JSX_SPREAD_CHILD, - &jsx_spread_child.span, - JSX_SPREAD_CHILD_RESERVED_BYTES, - false, - ); - // expression - self.update_reference_position(end_position + JSX_SPREAD_CHILD_EXPRESSION_OFFSET); - self.convert_expression(&jsx_spread_child.expr); - // end - self.add_end(end_position, &jsx_spread_child.span); - } - - fn convert_jsx_spread_element( - &mut self, - spread_element: &SpreadElement, - previous_element_end: u32, - ) { - let end_position = self.add_type_and_explicit_start( - &TYPE_JSX_SPREAD_ATTRIBUTE, - find_first_occurrence_outside_comment(self.code, b'{', previous_element_end), - JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES, - ); - // argument - self.update_reference_position(end_position + JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET); - self.convert_expression(&spread_element.expr); - // end - self.add_explicit_end( - end_position, - find_first_occurrence_outside_comment(self.code, b'}', spread_element.expr.span().hi.0 - 1) - + 1, - ); - } - - fn convert_jsx_text(&mut self, jsx_text: &JSXText) { - let end_position = self.add_type_and_start( - &TYPE_JSX_TEXT, - &jsx_text.span, - JSX_TEXT_RESERVED_BYTES, - false, - ); - // value - self.convert_string(&jsx_text.value, end_position + JSX_TEXT_VALUE_OFFSET); - // raw - self.convert_string(&jsx_text.raw, end_position + JSX_TEXT_RAW_OFFSET); - // end - self.add_end(end_position, &jsx_text.span); - } } pub fn convert_annotation(buffer: &mut Vec, annotation: &ConvertedAnnotation) { From d0d50828067be2825caedf99c0e256466ca750cd Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 2 Aug 2024 10:43:02 +0200 Subject: [PATCH 33/62] Make everything except the parse function only crate public --- .../src/ast_nodes/array_expression.rs | 2 +- rust/parse_ast/src/ast_nodes/array_pattern.rs | 2 +- .../ast_nodes/arrow_function_expression.rs | 4 +- .../src/ast_nodes/assignment_expression.rs | 4 +- .../src/ast_nodes/assignment_pattern.rs | 6 +- .../src/ast_nodes/await_expression.rs | 2 +- .../src/ast_nodes/binary_expression.rs | 6 +- .../src/ast_nodes/block_statement.rs | 6 +- .../src/ast_nodes/break_statement.rs | 2 +- .../src/ast_nodes/call_expression.rs | 8 +- rust/parse_ast/src/ast_nodes/catch_clause.rs | 2 +- .../src/ast_nodes/chain_expression.rs | 2 +- rust/parse_ast/src/ast_nodes/class_body.rs | 2 +- .../src/ast_nodes/class_declaration.rs | 2 +- .../src/ast_nodes/class_expression.rs | 6 +- .../src/ast_nodes/conditional_expression.rs | 2 +- .../src/ast_nodes/continue_statement.rs | 2 +- .../src/ast_nodes/debugger_statement.rs | 2 +- rust/parse_ast/src/ast_nodes/decorator.rs | 5 +- rust/parse_ast/src/ast_nodes/directive.rs | 2 +- .../src/ast_nodes/do_while_statement.rs | 2 +- .../src/ast_nodes/empty_statement.rs | 2 +- .../src/ast_nodes/export_all_declaration.rs | 4 +- .../ast_nodes/export_default_declaration.rs | 8 +- .../src/ast_nodes/export_named_declaration.rs | 2 +- .../src/ast_nodes/export_specifier.rs | 2 +- .../src/ast_nodes/expression_statement.rs | 2 +- .../src/ast_nodes/for_in_statement.rs | 2 +- .../src/ast_nodes/for_of_statement.rs | 4 +- rust/parse_ast/src/ast_nodes/for_statement.rs | 2 +- rust/parse_ast/src/ast_nodes/identifier.rs | 10 +- rust/parse_ast/src/ast_nodes/if_statement.rs | 2 +- .../src/ast_nodes/import_attribute.rs | 8 +- .../src/ast_nodes/import_declaration.rs | 6 +- .../src/ast_nodes/import_default_specifier.rs | 2 +- .../src/ast_nodes/import_expression.rs | 6 +- .../ast_nodes/import_namespace_specifier.rs | 2 +- .../src/ast_nodes/import_specifier.rs | 2 +- .../src/ast_nodes/labeled_statement.rs | 2 +- .../src/ast_nodes/literal_big_int.rs | 2 +- .../src/ast_nodes/literal_boolean.rs | 4 +- rust/parse_ast/src/ast_nodes/literal_null.rs | 2 +- .../parse_ast/src/ast_nodes/literal_number.rs | 2 +- .../src/ast_nodes/literal_reg_exp.rs | 2 +- .../parse_ast/src/ast_nodes/literal_string.rs | 2 +- .../src/ast_nodes/member_expression.rs | 18 +- rust/parse_ast/src/ast_nodes/meta_property.rs | 6 +- .../src/ast_nodes/method_definition.rs | 12 +- rust/parse_ast/src/ast_nodes/mod.rs | 192 ++++---- .../parse_ast/src/ast_nodes/new_expression.rs | 8 +- .../src/ast_nodes/object_expression.rs | 2 +- .../parse_ast/src/ast_nodes/object_pattern.rs | 2 +- rust/parse_ast/src/ast_nodes/panic_error.rs | 6 +- rust/parse_ast/src/ast_nodes/parse_error.rs | 4 +- .../src/ast_nodes/private_identifier.rs | 2 +- rust/parse_ast/src/ast_nodes/program.rs | 10 +- rust/parse_ast/src/ast_nodes/property.rs | 10 +- .../src/ast_nodes/property_definition.rs | 10 +- rust/parse_ast/src/ast_nodes/rest_element.rs | 4 +- .../src/ast_nodes/return_statement.rs | 2 +- .../src/ast_nodes/sequence_expression.rs | 2 +- .../src/ast_nodes/shared/class_node.rs | 6 +- .../src/ast_nodes/shared/function_node.rs | 4 +- .../parse_ast/src/ast_nodes/spread_element.rs | 4 +- rust/parse_ast/src/ast_nodes/static_block.rs | 2 +- rust/parse_ast/src/ast_nodes/super_element.rs | 2 +- rust/parse_ast/src/ast_nodes/switch_case.rs | 2 +- .../src/ast_nodes/switch_statement.rs | 2 +- .../ast_nodes/tagged_template_expression.rs | 2 +- .../src/ast_nodes/template_element.rs | 4 +- .../src/ast_nodes/template_literal.rs | 6 +- .../src/ast_nodes/this_expression.rs | 2 +- .../src/ast_nodes/throw_statement.rs | 2 +- rust/parse_ast/src/ast_nodes/try_statement.rs | 6 +- .../src/ast_nodes/unary_expression.rs | 6 +- .../src/ast_nodes/update_expression.rs | 2 +- .../src/ast_nodes/variable_declaration.rs | 14 +- .../src/ast_nodes/variable_declarator.rs | 6 +- .../src/ast_nodes/while_statement.rs | 2 +- .../src/ast_nodes/yield_expression.rs | 4 +- rust/parse_ast/src/convert_ast.rs | 4 +- rust/parse_ast/src/convert_ast/annotations.rs | 18 +- rust/parse_ast/src/convert_ast/converter.rs | 44 +- .../src/convert_ast/converter/analyze_code.rs | 6 +- .../convert_ast/converter/ast_constants.rs | 444 +++++++++--------- .../convert_ast/converter/string_constants.rs | 126 ++--- .../convert_ast/converter/utf16_positions.rs | 27 +- rust/parse_ast/src/error_emit.rs | 6 +- 88 files changed, 606 insertions(+), 590 deletions(-) diff --git a/rust/parse_ast/src/ast_nodes/array_expression.rs b/rust/parse_ast/src/ast_nodes/array_expression.rs index ea999b5d43f..57bfe1f7992 100644 --- a/rust/parse_ast/src/ast_nodes/array_expression.rs +++ b/rust/parse_ast/src/ast_nodes/array_expression.rs @@ -6,7 +6,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_array_expression(&mut self, array_literal: &ArrayLit) { + pub(crate) fn store_array_expression(&mut self, array_literal: &ArrayLit) { let end_position = self.add_type_and_start( &TYPE_ARRAY_EXPRESSION, &array_literal.span, diff --git a/rust/parse_ast/src/ast_nodes/array_pattern.rs b/rust/parse_ast/src/ast_nodes/array_pattern.rs index 90997dda110..913be200715 100644 --- a/rust/parse_ast/src/ast_nodes/array_pattern.rs +++ b/rust/parse_ast/src/ast_nodes/array_pattern.rs @@ -6,7 +6,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_array_pattern(&mut self, array_pattern: &ArrayPat) { + pub(crate) fn store_array_pattern(&mut self, array_pattern: &ArrayPat) { let end_position = self.add_type_and_start( &TYPE_ARRAY_PATTERN, &array_pattern.span, diff --git a/rust/parse_ast/src/ast_nodes/arrow_function_expression.rs b/rust/parse_ast/src/ast_nodes/arrow_function_expression.rs index c737e458045..8ac6e1fd7bc 100644 --- a/rust/parse_ast/src/ast_nodes/arrow_function_expression.rs +++ b/rust/parse_ast/src/ast_nodes/arrow_function_expression.rs @@ -1,16 +1,16 @@ use swc_ecma_ast::{ArrowExpr, BlockStmtOrExpr}; use crate::convert_ast::annotations::AnnotationKind; +use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ ARROW_FUNCTION_EXPRESSION_ANNOTATIONS_OFFSET, ARROW_FUNCTION_EXPRESSION_BODY_OFFSET, ARROW_FUNCTION_EXPRESSION_PARAMS_OFFSET, ARROW_FUNCTION_EXPRESSION_RESERVED_BYTES, TYPE_ARROW_FUNCTION_EXPRESSION, }; -use crate::convert_ast::converter::{convert_annotation, AstConverter}; use crate::store_arrow_function_expression_flags; impl<'a> AstConverter<'a> { - pub fn store_arrow_function_expression(&mut self, arrow_expression: &ArrowExpr) { + pub(crate) fn store_arrow_function_expression(&mut self, arrow_expression: &ArrowExpr) { let end_position = self.add_type_and_start( &TYPE_ARROW_FUNCTION_EXPRESSION, &arrow_expression.span, diff --git a/rust/parse_ast/src/ast_nodes/assignment_expression.rs b/rust/parse_ast/src/ast_nodes/assignment_expression.rs index 1b159de3e7a..19c934e915b 100644 --- a/rust/parse_ast/src/ast_nodes/assignment_expression.rs +++ b/rust/parse_ast/src/ast_nodes/assignment_expression.rs @@ -1,16 +1,16 @@ use swc_ecma_ast::{AssignExpr, AssignOp}; +use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ STRING_ADDASSIGN, STRING_ANDASSIGN, STRING_ASSIGN, STRING_BITANDASSIGN, STRING_BITORASSIGN, STRING_BITXORASSIGN, STRING_DIVASSIGN, STRING_EXPASSIGN, STRING_LSHIFTASSIGN, STRING_MODASSIGN, STRING_MULASSIGN, STRING_NULLISHASSIGN, STRING_ORASSIGN, STRING_RSHIFTASSIGN, STRING_SUBASSIGN, STRING_ZEROFILLRSHIFTASSIGN, }; -use crate::convert_ast::converter::AstConverter; use crate::store_assignment_expression; impl<'a> AstConverter<'a> { - pub fn store_assignment_expression(&mut self, assignment_expression: &AssignExpr) { + pub(crate) fn store_assignment_expression(&mut self, assignment_expression: &AssignExpr) { store_assignment_expression!( self, span => assignment_expression.span, diff --git a/rust/parse_ast/src/ast_nodes/assignment_pattern.rs b/rust/parse_ast/src/ast_nodes/assignment_pattern.rs index 05a0c8a26ec..3e26ccfaa43 100644 --- a/rust/parse_ast/src/ast_nodes/assignment_pattern.rs +++ b/rust/parse_ast/src/ast_nodes/assignment_pattern.rs @@ -8,7 +8,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_assignment_pattern_and_get_left_position( + pub(crate) fn store_assignment_pattern_and_get_left_position( &mut self, span: &Span, left: PatternOrIdentifier, @@ -37,7 +37,7 @@ impl<'a> AstConverter<'a> { left_position } - pub fn convert_assignment_pattern(&mut self, assignment_pattern: &AssignPat) { + pub(crate) fn convert_assignment_pattern(&mut self, assignment_pattern: &AssignPat) { self.store_assignment_pattern_and_get_left_position( &assignment_pattern.span, PatternOrIdentifier::Pattern(&assignment_pattern.left), @@ -46,7 +46,7 @@ impl<'a> AstConverter<'a> { } } -pub enum PatternOrIdentifier<'a> { +pub(crate) enum PatternOrIdentifier<'a> { Pattern(&'a Pat), Identifier(&'a Ident), } diff --git a/rust/parse_ast/src/ast_nodes/await_expression.rs b/rust/parse_ast/src/ast_nodes/await_expression.rs index 820a7c9d1c8..950ec79f210 100644 --- a/rust/parse_ast/src/ast_nodes/await_expression.rs +++ b/rust/parse_ast/src/ast_nodes/await_expression.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_await_expression; impl<'a> AstConverter<'a> { - pub fn store_await_expression(&mut self, await_expression: &AwaitExpr) { + pub(crate) fn store_await_expression(&mut self, await_expression: &AwaitExpr) { store_await_expression!( self, span => await_expression.span, diff --git a/rust/parse_ast/src/ast_nodes/binary_expression.rs b/rust/parse_ast/src/ast_nodes/binary_expression.rs index 9cd97046d41..17ba3c67ce0 100644 --- a/rust/parse_ast/src/ast_nodes/binary_expression.rs +++ b/rust/parse_ast/src/ast_nodes/binary_expression.rs @@ -1,20 +1,20 @@ -use swc_ecma_ast::{BinExpr, BinaryOp}; +use swc_ecma_ast::{BinaryOp, BinExpr}; use crate::convert_ast::converter::ast_constants::{ BINARY_EXPRESSION_LEFT_OFFSET, BINARY_EXPRESSION_OPERATOR_OFFSET, BINARY_EXPRESSION_RESERVED_BYTES, BINARY_EXPRESSION_RIGHT_OFFSET, TYPE_BINARY_EXPRESSION, TYPE_LOGICAL_EXPRESSION, }; +use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ STRING_ADD, STRING_BITAND, STRING_BITOR, STRING_BITXOR, STRING_DIV, STRING_EQEQ, STRING_EQEQEQ, STRING_EXP, STRING_GT, STRING_GTEQ, STRING_IN, STRING_INSTANCEOF, STRING_LOGICALAND, STRING_LOGICALOR, STRING_LSHIFT, STRING_LT, STRING_LTEQ, STRING_MOD, STRING_MUL, STRING_NOTEQ, STRING_NOTEQEQ, STRING_NULLISHCOALESCING, STRING_RSHIFT, STRING_SUB, STRING_ZEROFILLRSHIFT, }; -use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_binary_expression(&mut self, binary_expression: &BinExpr) { + pub(crate) fn store_binary_expression(&mut self, binary_expression: &BinExpr) { let end_position = self.add_type_and_start( match binary_expression.op { BinaryOp::LogicalOr | BinaryOp::LogicalAnd | BinaryOp::NullishCoalescing => { diff --git a/rust/parse_ast/src/ast_nodes/block_statement.rs b/rust/parse_ast/src/ast_nodes/block_statement.rs index fec1816c0fc..dcee9b291da 100644 --- a/rust/parse_ast/src/ast_nodes/block_statement.rs +++ b/rust/parse_ast/src/ast_nodes/block_statement.rs @@ -6,7 +6,11 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_block_statement(&mut self, block_statement: &BlockStmt, check_directive: bool) { + pub(crate) fn store_block_statement( + &mut self, + block_statement: &BlockStmt, + check_directive: bool, + ) { let end_position = self.add_type_and_start( &TYPE_BLOCK_STATEMENT, &block_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/break_statement.rs b/rust/parse_ast/src/ast_nodes/break_statement.rs index ef54b723d1a..c92c4133fa7 100644 --- a/rust/parse_ast/src/ast_nodes/break_statement.rs +++ b/rust/parse_ast/src/ast_nodes/break_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_break_statement; impl<'a> AstConverter<'a> { - pub fn store_break_statement(&mut self, break_statement: &BreakStmt) { + pub(crate) fn store_break_statement(&mut self, break_statement: &BreakStmt) { store_break_statement!( self, span => break_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/call_expression.rs b/rust/parse_ast/src/ast_nodes/call_expression.rs index e8d3c526575..30916d872f5 100644 --- a/rust/parse_ast/src/ast_nodes/call_expression.rs +++ b/rust/parse_ast/src/ast_nodes/call_expression.rs @@ -2,15 +2,15 @@ use swc_common::Span; use swc_ecma_ast::{Expr, ExprOrSpread, OptCall, Super}; use crate::convert_ast::annotations::AnnotationKind; +use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ CALL_EXPRESSION_ANNOTATIONS_OFFSET, CALL_EXPRESSION_ARGUMENTS_OFFSET, CALL_EXPRESSION_CALLEE_OFFSET, CALL_EXPRESSION_RESERVED_BYTES, TYPE_CALL_EXPRESSION, }; -use crate::convert_ast::converter::{convert_annotation, AstConverter}; use crate::store_call_expression_flags; impl<'a> AstConverter<'a> { - pub fn store_call_expression( + pub(crate) fn store_call_expression( &mut self, span: &Span, is_optional: bool, @@ -70,7 +70,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, span); } - pub fn convert_optional_call( + pub(crate) fn convert_optional_call( &mut self, optional_call: &OptCall, is_optional: bool, @@ -86,7 +86,7 @@ impl<'a> AstConverter<'a> { } } -pub enum StoredCallee<'a> { +pub(crate) enum StoredCallee<'a> { Expression(&'a Expr), Super(&'a Super), } diff --git a/rust/parse_ast/src/ast_nodes/catch_clause.rs b/rust/parse_ast/src/ast_nodes/catch_clause.rs index 78e85906e15..90323376569 100644 --- a/rust/parse_ast/src/ast_nodes/catch_clause.rs +++ b/rust/parse_ast/src/ast_nodes/catch_clause.rs @@ -7,7 +7,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_catch_clause(&mut self, catch_clause: &CatchClause) { + pub(crate) fn store_catch_clause(&mut self, catch_clause: &CatchClause) { let end_position = self.add_type_and_start( &TYPE_CATCH_CLAUSE, &catch_clause.span, diff --git a/rust/parse_ast/src/ast_nodes/chain_expression.rs b/rust/parse_ast/src/ast_nodes/chain_expression.rs index 4d29a797f69..f034d8cd5ea 100644 --- a/rust/parse_ast/src/ast_nodes/chain_expression.rs +++ b/rust/parse_ast/src/ast_nodes/chain_expression.rs @@ -6,7 +6,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_chain_expression( + pub(crate) fn store_chain_expression( &mut self, optional_chain_expression: &OptChainExpr, is_chained: bool, diff --git a/rust/parse_ast/src/ast_nodes/class_body.rs b/rust/parse_ast/src/ast_nodes/class_body.rs index 7d187e60441..696ce2434dc 100644 --- a/rust/parse_ast/src/ast_nodes/class_body.rs +++ b/rust/parse_ast/src/ast_nodes/class_body.rs @@ -6,7 +6,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_class_body(&mut self, class_members: &[ClassMember], start: u32, end: u32) { + pub(crate) fn store_class_body(&mut self, class_members: &[ClassMember], start: u32, end: u32) { let end_position = self.add_type_and_explicit_start(&TYPE_CLASS_BODY, start, CLASS_BODY_RESERVED_BYTES); let class_members_filtered: Vec<&ClassMember> = class_members diff --git a/rust/parse_ast/src/ast_nodes/class_declaration.rs b/rust/parse_ast/src/ast_nodes/class_declaration.rs index 73cdd733e0f..7b79633f8fe 100644 --- a/rust/parse_ast/src/ast_nodes/class_declaration.rs +++ b/rust/parse_ast/src/ast_nodes/class_declaration.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::ast_constants::TYPE_CLASS_DECLARATION; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_class_declaration(&mut self, class_declaration: &ClassDecl) { + pub(crate) fn store_class_declaration(&mut self, class_declaration: &ClassDecl) { self.store_class_node( &TYPE_CLASS_DECLARATION, Some(&class_declaration.ident), diff --git a/rust/parse_ast/src/ast_nodes/class_expression.rs b/rust/parse_ast/src/ast_nodes/class_expression.rs index c5515fe1ef5..dea6030d841 100644 --- a/rust/parse_ast/src/ast_nodes/class_expression.rs +++ b/rust/parse_ast/src/ast_nodes/class_expression.rs @@ -3,7 +3,11 @@ use swc_ecma_ast::ClassExpr; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_class_expression(&mut self, class_expression: &ClassExpr, node_type: &[u8; 4]) { + pub(crate) fn store_class_expression( + &mut self, + class_expression: &ClassExpr, + node_type: &[u8; 4], + ) { self.store_class_node( node_type, class_expression.ident.as_ref(), diff --git a/rust/parse_ast/src/ast_nodes/conditional_expression.rs b/rust/parse_ast/src/ast_nodes/conditional_expression.rs index 402d14981d2..13333943eae 100644 --- a/rust/parse_ast/src/ast_nodes/conditional_expression.rs +++ b/rust/parse_ast/src/ast_nodes/conditional_expression.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_conditional_expression; impl<'a> AstConverter<'a> { - pub fn store_conditional_expression(&mut self, conditional_expression: &CondExpr) { + pub(crate) fn store_conditional_expression(&mut self, conditional_expression: &CondExpr) { store_conditional_expression!( self, span => conditional_expression.span, diff --git a/rust/parse_ast/src/ast_nodes/continue_statement.rs b/rust/parse_ast/src/ast_nodes/continue_statement.rs index 6614f7910ef..6d652d290e8 100644 --- a/rust/parse_ast/src/ast_nodes/continue_statement.rs +++ b/rust/parse_ast/src/ast_nodes/continue_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_continue_statement; impl<'a> AstConverter<'a> { - pub fn store_continue_statement(&mut self, continue_statement: &ContinueStmt) { + pub(crate) fn store_continue_statement(&mut self, continue_statement: &ContinueStmt) { store_continue_statement!( self, span => continue_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/debugger_statement.rs b/rust/parse_ast/src/ast_nodes/debugger_statement.rs index ac3ea46808f..5b35df24b91 100644 --- a/rust/parse_ast/src/ast_nodes/debugger_statement.rs +++ b/rust/parse_ast/src/ast_nodes/debugger_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_debugger_statement; impl<'a> AstConverter<'a> { - pub fn store_debugger_statement(&mut self, debugger_statement: &DebuggerStmt) { + pub(crate) fn store_debugger_statement(&mut self, debugger_statement: &DebuggerStmt) { store_debugger_statement!(self, span => debugger_statement.span); } } diff --git a/rust/parse_ast/src/ast_nodes/decorator.rs b/rust/parse_ast/src/ast_nodes/decorator.rs index 128fb730d93..61bdc265b4e 100644 --- a/rust/parse_ast/src/ast_nodes/decorator.rs +++ b/rust/parse_ast/src/ast_nodes/decorator.rs @@ -1,9 +1,10 @@ +use swc_ecma_ast::Decorator; + use crate::convert_ast::converter::AstConverter; use crate::store_decorator; -use swc_ecma_ast::Decorator; impl<'a> AstConverter<'a> { - pub fn store_decorator(&mut self, decorator: &Decorator) { + pub(crate) fn store_decorator(&mut self, decorator: &Decorator) { store_decorator!(self, span => decorator.span, expression=>[decorator.expr, convert_expression]); } } diff --git a/rust/parse_ast/src/ast_nodes/directive.rs b/rust/parse_ast/src/ast_nodes/directive.rs index 6290f31519b..ed7bf34d90c 100644 --- a/rust/parse_ast/src/ast_nodes/directive.rs +++ b/rust/parse_ast/src/ast_nodes/directive.rs @@ -5,7 +5,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_directive; impl<'a> AstConverter<'a> { - pub fn store_directive(&mut self, expression_statement: &ExprStmt, directive: &JsWord) { + pub(crate) fn store_directive(&mut self, expression_statement: &ExprStmt, directive: &JsWord) { store_directive!( self, span => expression_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/do_while_statement.rs b/rust/parse_ast/src/ast_nodes/do_while_statement.rs index 01cb24d331f..bf00756ccd3 100644 --- a/rust/parse_ast/src/ast_nodes/do_while_statement.rs +++ b/rust/parse_ast/src/ast_nodes/do_while_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_do_while_statement; impl<'a> AstConverter<'a> { - pub fn store_do_while_statement(&mut self, do_while_statement: &DoWhileStmt) { + pub(crate) fn store_do_while_statement(&mut self, do_while_statement: &DoWhileStmt) { store_do_while_statement!( self, span => do_while_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/empty_statement.rs b/rust/parse_ast/src/ast_nodes/empty_statement.rs index 22d9d147b52..9206fbe3ad5 100644 --- a/rust/parse_ast/src/ast_nodes/empty_statement.rs +++ b/rust/parse_ast/src/ast_nodes/empty_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_empty_statement; impl<'a> AstConverter<'a> { - pub fn store_empty_statement(&mut self, empty_statement: &EmptyStmt) { + pub(crate) fn store_empty_statement(&mut self, empty_statement: &EmptyStmt) { store_empty_statement!(self, span => empty_statement.span); } } diff --git a/rust/parse_ast/src/ast_nodes/export_all_declaration.rs b/rust/parse_ast/src/ast_nodes/export_all_declaration.rs index 57a8c2efe9e..fd0ac5c1c5f 100644 --- a/rust/parse_ast/src/ast_nodes/export_all_declaration.rs +++ b/rust/parse_ast/src/ast_nodes/export_all_declaration.rs @@ -9,7 +9,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_export_all_declaration( + pub(crate) fn store_export_all_declaration( &mut self, span: &Span, source: &Str, @@ -39,7 +39,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, span); } - pub fn convert_export_all(&mut self, export_all: &ExportAll) { + pub(crate) fn convert_export_all(&mut self, export_all: &ExportAll) { self.store_export_all_declaration(&export_all.span, &export_all.src, &export_all.with, None); } } diff --git a/rust/parse_ast/src/ast_nodes/export_default_declaration.rs b/rust/parse_ast/src/ast_nodes/export_default_declaration.rs index d1c557b4f58..c673e2904c6 100644 --- a/rust/parse_ast/src/ast_nodes/export_default_declaration.rs +++ b/rust/parse_ast/src/ast_nodes/export_default_declaration.rs @@ -8,7 +8,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_export_default_declaration( + pub(crate) fn store_export_default_declaration( &mut self, span: &Span, expression: StoredDefaultExportExpression, @@ -42,7 +42,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, span); } - pub fn convert_export_default_declaration( + pub(crate) fn convert_export_default_declaration( &mut self, export_default_declaration: &ExportDefaultDecl, ) { @@ -62,7 +62,7 @@ impl<'a> AstConverter<'a> { ); } - pub fn convert_export_default_expression( + pub(crate) fn convert_export_default_expression( &mut self, export_default_expression: &ExportDefaultExpr, ) { @@ -73,7 +73,7 @@ impl<'a> AstConverter<'a> { } } -pub enum StoredDefaultExportExpression<'a> { +pub(crate) enum StoredDefaultExportExpression<'a> { Expression(&'a Expr), Class(&'a ClassExpr), Function(&'a FnExpr), diff --git a/rust/parse_ast/src/ast_nodes/export_named_declaration.rs b/rust/parse_ast/src/ast_nodes/export_named_declaration.rs index c195afdc097..73cd62eeb6f 100644 --- a/rust/parse_ast/src/ast_nodes/export_named_declaration.rs +++ b/rust/parse_ast/src/ast_nodes/export_named_declaration.rs @@ -9,7 +9,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_export_named_declaration( + pub(crate) fn store_export_named_declaration( &mut self, span: &Span, specifiers: &[ExportSpecifier], diff --git a/rust/parse_ast/src/ast_nodes/export_specifier.rs b/rust/parse_ast/src/ast_nodes/export_specifier.rs index adb8c09cf73..5319746cdeb 100644 --- a/rust/parse_ast/src/ast_nodes/export_specifier.rs +++ b/rust/parse_ast/src/ast_nodes/export_specifier.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_export_specifier; impl<'a> AstConverter<'a> { - pub fn store_export_specifier(&mut self, export_named_specifier: &ExportNamedSpecifier) { + pub(crate) fn store_export_specifier(&mut self, export_named_specifier: &ExportNamedSpecifier) { store_export_specifier!( self, span => &export_named_specifier.span, diff --git a/rust/parse_ast/src/ast_nodes/expression_statement.rs b/rust/parse_ast/src/ast_nodes/expression_statement.rs index 7fed6d83683..b71d13f2aad 100644 --- a/rust/parse_ast/src/ast_nodes/expression_statement.rs +++ b/rust/parse_ast/src/ast_nodes/expression_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_expression_statement; impl<'a> AstConverter<'a> { - pub fn store_expression_statement(&mut self, expression_statement: &ExprStmt) { + pub(crate) fn store_expression_statement(&mut self, expression_statement: &ExprStmt) { store_expression_statement!( self, span => &expression_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/for_in_statement.rs b/rust/parse_ast/src/ast_nodes/for_in_statement.rs index 72bf9e3dda9..8a584c8f49f 100644 --- a/rust/parse_ast/src/ast_nodes/for_in_statement.rs +++ b/rust/parse_ast/src/ast_nodes/for_in_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_for_in_statement; impl<'a> AstConverter<'a> { - pub fn store_for_in_statement(&mut self, for_in_statement: &ForInStmt) { + pub(crate) fn store_for_in_statement(&mut self, for_in_statement: &ForInStmt) { store_for_in_statement!( self, span => &for_in_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/for_of_statement.rs b/rust/parse_ast/src/ast_nodes/for_of_statement.rs index a57e69cfef9..5602cba3dac 100644 --- a/rust/parse_ast/src/ast_nodes/for_of_statement.rs +++ b/rust/parse_ast/src/ast_nodes/for_of_statement.rs @@ -1,10 +1,10 @@ use swc_ecma_ast::ForOfStmt; -use crate::convert_ast::converter::AstConverter; use crate::{store_for_of_statement, store_for_of_statement_flags}; +use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_for_of_statement(&mut self, for_of_statement: &ForOfStmt) { + pub(crate) fn store_for_of_statement(&mut self, for_of_statement: &ForOfStmt) { store_for_of_statement!( self, span => &for_of_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/for_statement.rs b/rust/parse_ast/src/ast_nodes/for_statement.rs index 1d16325e7ba..fd797ee7047 100644 --- a/rust/parse_ast/src/ast_nodes/for_statement.rs +++ b/rust/parse_ast/src/ast_nodes/for_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_for_statement; impl<'a> AstConverter<'a> { - pub fn store_for_statement(&mut self, for_statement: &ForStmt) { + pub(crate) fn store_for_statement(&mut self, for_statement: &ForStmt) { store_for_statement!( self, span => &for_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/identifier.rs b/rust/parse_ast/src/ast_nodes/identifier.rs index a92658dc11c..553a5fc3cc0 100644 --- a/rust/parse_ast/src/ast_nodes/identifier.rs +++ b/rust/parse_ast/src/ast_nodes/identifier.rs @@ -1,12 +1,12 @@ use swc_ecma_ast::{BindingIdent, Ident, IdentName}; use crate::convert_ast::converter::ast_constants::{ - IDENTIFIER_NAME_OFFSET, IDENTIFIER_RESERVED_BYTES, TYPE_IDENTIFIER, + IDENTIFIER_NAME_OFFSET, IDENTIFIER_RESERVED_BYTES, TYPE_IDENTIFIER, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_identifier(&mut self, start: u32, end: u32, name: &str) { + pub(crate) fn store_identifier(&mut self, start: u32, end: u32, name: &str) { let end_position = self.add_type_and_explicit_start(&TYPE_IDENTIFIER, start, IDENTIFIER_RESERVED_BYTES); // name @@ -15,18 +15,18 @@ impl<'a> AstConverter<'a> { self.add_explicit_end(end_position, end); } - pub fn convert_binding_identifier(&mut self, binding_identifier: &BindingIdent) { + pub(crate) fn convert_binding_identifier(&mut self, binding_identifier: &BindingIdent) { self.convert_identifier(&binding_identifier.id); } - pub fn convert_identifier(&mut self, identifier: &Ident) { + pub(crate) fn convert_identifier(&mut self, identifier: &Ident) { self.store_identifier( identifier.span.lo.0 - 1, identifier.span.hi.0 - 1, &identifier.sym, ); } - pub fn convert_identifier_name(&mut self, identifier: &IdentName) { + pub(crate) fn convert_identifier_name(&mut self, identifier: &IdentName) { self.store_identifier( identifier.span.lo.0 - 1, identifier.span.hi.0 - 1, diff --git a/rust/parse_ast/src/ast_nodes/if_statement.rs b/rust/parse_ast/src/ast_nodes/if_statement.rs index e093372cbe9..c8dcb86f319 100644 --- a/rust/parse_ast/src/ast_nodes/if_statement.rs +++ b/rust/parse_ast/src/ast_nodes/if_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_if_statement; impl<'a> AstConverter<'a> { - pub fn store_if_statement(&mut self, if_statement: &IfStmt) { + pub(crate) fn store_if_statement(&mut self, if_statement: &IfStmt) { store_if_statement!( self, span => &if_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/import_attribute.rs b/rust/parse_ast/src/ast_nodes/import_attribute.rs index 829ab14bfe5..0bd4187886f 100644 --- a/rust/parse_ast/src/ast_nodes/import_attribute.rs +++ b/rust/parse_ast/src/ast_nodes/import_attribute.rs @@ -2,13 +2,13 @@ use swc_common::Spanned; use swc_ecma_ast::{KeyValueProp, ObjectLit, Prop, PropOrSpread}; use crate::convert_ast::converter::ast_constants::{ - IMPORT_ATTRIBUTE_KEY_OFFSET, IMPORT_ATTRIBUTE_RESERVED_BYTES, IMPORT_ATTRIBUTE_VALUE_OFFSET, - TYPE_IMPORT_ATTRIBUTE, + IMPORT_ATTRIBUTE_KEY_OFFSET, IMPORT_ATTRIBUTE_RESERVED_BYTES, IMPORT_ATTRIBUTE_VALUE_OFFSET, + TYPE_IMPORT_ATTRIBUTE, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_import_attribute(&mut self, key_value_property: &KeyValueProp) { + pub(crate) fn store_import_attribute(&mut self, key_value_property: &KeyValueProp) { // type let end_position = self.add_type_and_start( &TYPE_IMPORT_ATTRIBUTE, @@ -25,7 +25,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &key_value_property.span()); } - pub fn store_import_attributes( + pub(crate) fn store_import_attributes( &mut self, with: &Option>, reference_position: usize, diff --git a/rust/parse_ast/src/ast_nodes/import_declaration.rs b/rust/parse_ast/src/ast_nodes/import_declaration.rs index af58998c67d..0734b38a9df 100644 --- a/rust/parse_ast/src/ast_nodes/import_declaration.rs +++ b/rust/parse_ast/src/ast_nodes/import_declaration.rs @@ -1,13 +1,13 @@ use swc_ecma_ast::ImportDecl; use crate::convert_ast::converter::ast_constants::{ - IMPORT_DECLARATION_ATTRIBUTES_OFFSET, IMPORT_DECLARATION_RESERVED_BYTES, - IMPORT_DECLARATION_SOURCE_OFFSET, IMPORT_DECLARATION_SPECIFIERS_OFFSET, TYPE_IMPORT_DECLARATION, + IMPORT_DECLARATION_ATTRIBUTES_OFFSET, IMPORT_DECLARATION_RESERVED_BYTES, + IMPORT_DECLARATION_SOURCE_OFFSET, IMPORT_DECLARATION_SPECIFIERS_OFFSET, TYPE_IMPORT_DECLARATION, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_import_declaration(&mut self, import_declaration: &ImportDecl) { + pub(crate) fn store_import_declaration(&mut self, import_declaration: &ImportDecl) { let end_position = self.add_type_and_start( &TYPE_IMPORT_DECLARATION, &import_declaration.span, diff --git a/rust/parse_ast/src/ast_nodes/import_default_specifier.rs b/rust/parse_ast/src/ast_nodes/import_default_specifier.rs index 689bd5f4ec2..70c8d5bb7a5 100644 --- a/rust/parse_ast/src/ast_nodes/import_default_specifier.rs +++ b/rust/parse_ast/src/ast_nodes/import_default_specifier.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_import_default_specifier; impl<'a> AstConverter<'a> { - pub fn store_import_default_specifier( + pub(crate) fn store_import_default_specifier( &mut self, import_default_specifier: &ImportDefaultSpecifier, ) { diff --git a/rust/parse_ast/src/ast_nodes/import_expression.rs b/rust/parse_ast/src/ast_nodes/import_expression.rs index 2232b0f5db9..966623e9ec3 100644 --- a/rust/parse_ast/src/ast_nodes/import_expression.rs +++ b/rust/parse_ast/src/ast_nodes/import_expression.rs @@ -2,13 +2,13 @@ use swc_common::Span; use swc_ecma_ast::ExprOrSpread; use crate::convert_ast::converter::ast_constants::{ - IMPORT_EXPRESSION_OPTIONS_OFFSET, IMPORT_EXPRESSION_RESERVED_BYTES, - IMPORT_EXPRESSION_SOURCE_OFFSET, TYPE_IMPORT_EXPRESSION, + IMPORT_EXPRESSION_OPTIONS_OFFSET, IMPORT_EXPRESSION_RESERVED_BYTES, + IMPORT_EXPRESSION_SOURCE_OFFSET, TYPE_IMPORT_EXPRESSION, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_import_expression(&mut self, span: &Span, arguments: &[ExprOrSpread]) { + pub(crate) fn store_import_expression(&mut self, span: &Span, arguments: &[ExprOrSpread]) { let end_position = self.add_type_and_start( &TYPE_IMPORT_EXPRESSION, span, diff --git a/rust/parse_ast/src/ast_nodes/import_namespace_specifier.rs b/rust/parse_ast/src/ast_nodes/import_namespace_specifier.rs index f7ffe93f398..0128b0e5cd5 100644 --- a/rust/parse_ast/src/ast_nodes/import_namespace_specifier.rs +++ b/rust/parse_ast/src/ast_nodes/import_namespace_specifier.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_import_namespace_specifier; impl<'a> AstConverter<'a> { - pub fn store_import_namespace_specifier( + pub(crate) fn store_import_namespace_specifier( &mut self, import_namespace_specifier: &ImportStarAsSpecifier, ) { diff --git a/rust/parse_ast/src/ast_nodes/import_specifier.rs b/rust/parse_ast/src/ast_nodes/import_specifier.rs index 1d02bf0677d..3c162702213 100644 --- a/rust/parse_ast/src/ast_nodes/import_specifier.rs +++ b/rust/parse_ast/src/ast_nodes/import_specifier.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_import_specifier; impl<'a> AstConverter<'a> { - pub fn store_import_specifier(&mut self, import_named_specifier: &ImportNamedSpecifier) { + pub(crate) fn store_import_specifier(&mut self, import_named_specifier: &ImportNamedSpecifier) { store_import_specifier!( self, span => &import_named_specifier.span, diff --git a/rust/parse_ast/src/ast_nodes/labeled_statement.rs b/rust/parse_ast/src/ast_nodes/labeled_statement.rs index 0f2bd3cd07e..f2a8dc44ba3 100644 --- a/rust/parse_ast/src/ast_nodes/labeled_statement.rs +++ b/rust/parse_ast/src/ast_nodes/labeled_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_labeled_statement; impl<'a> AstConverter<'a> { - pub fn store_labeled_statement(&mut self, labeled_statement: &LabeledStmt) { + pub(crate) fn store_labeled_statement(&mut self, labeled_statement: &LabeledStmt) { store_labeled_statement!( self, span => &labeled_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/literal_big_int.rs b/rust/parse_ast/src/ast_nodes/literal_big_int.rs index 5a98704fd3e..2ca27c3aa26 100644 --- a/rust/parse_ast/src/ast_nodes/literal_big_int.rs +++ b/rust/parse_ast/src/ast_nodes/literal_big_int.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_literal_big_int; impl<'a> AstConverter<'a> { - pub fn store_literal_bigint(&mut self, bigint: &BigInt) { + pub(crate) fn store_literal_bigint(&mut self, bigint: &BigInt) { store_literal_big_int!( self, span => &bigint.span, diff --git a/rust/parse_ast/src/ast_nodes/literal_boolean.rs b/rust/parse_ast/src/ast_nodes/literal_boolean.rs index 9c84f9dfb5a..7c9768ee261 100644 --- a/rust/parse_ast/src/ast_nodes/literal_boolean.rs +++ b/rust/parse_ast/src/ast_nodes/literal_boolean.rs @@ -1,10 +1,10 @@ use swc_ecma_ast::Bool; -use crate::convert_ast::converter::AstConverter; use crate::{store_literal_boolean, store_literal_boolean_flags}; +use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_literal_boolean(&mut self, literal: &Bool) { + pub(crate) fn store_literal_boolean(&mut self, literal: &Bool) { store_literal_boolean!( self, span => &literal.span, diff --git a/rust/parse_ast/src/ast_nodes/literal_null.rs b/rust/parse_ast/src/ast_nodes/literal_null.rs index 9c46f838c71..541007ff3a5 100644 --- a/rust/parse_ast/src/ast_nodes/literal_null.rs +++ b/rust/parse_ast/src/ast_nodes/literal_null.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_literal_null; impl<'a> AstConverter<'a> { - pub fn store_literal_null(&mut self, literal: &Null) { + pub(crate) fn store_literal_null(&mut self, literal: &Null) { store_literal_null!( self, span => &literal.span diff --git a/rust/parse_ast/src/ast_nodes/literal_number.rs b/rust/parse_ast/src/ast_nodes/literal_number.rs index 64cc5fa32ec..6c8d9aa3d37 100644 --- a/rust/parse_ast/src/ast_nodes/literal_number.rs +++ b/rust/parse_ast/src/ast_nodes/literal_number.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_literal_number; impl<'a> AstConverter<'a> { - pub fn store_literal_number(&mut self, literal: &Number) { + pub(crate) fn store_literal_number(&mut self, literal: &Number) { store_literal_number!( self, span => &literal.span, diff --git a/rust/parse_ast/src/ast_nodes/literal_reg_exp.rs b/rust/parse_ast/src/ast_nodes/literal_reg_exp.rs index 3e730e4f4d5..f731d3efb20 100644 --- a/rust/parse_ast/src/ast_nodes/literal_reg_exp.rs +++ b/rust/parse_ast/src/ast_nodes/literal_reg_exp.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_literal_reg_exp; impl<'a> AstConverter<'a> { - pub fn store_literal_regex(&mut self, regex: &Regex) { + pub(crate) fn store_literal_regex(&mut self, regex: &Regex) { store_literal_reg_exp!( self, span => ®ex.span, diff --git a/rust/parse_ast/src/ast_nodes/literal_string.rs b/rust/parse_ast/src/ast_nodes/literal_string.rs index 0b475512e23..373db0b5a26 100644 --- a/rust/parse_ast/src/ast_nodes/literal_string.rs +++ b/rust/parse_ast/src/ast_nodes/literal_string.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_literal_string; impl<'a> AstConverter<'a> { - pub fn store_literal_string(&mut self, literal: &Str) { + pub(crate) fn store_literal_string(&mut self, literal: &Str) { store_literal_string!( self, span => &literal.span, diff --git a/rust/parse_ast/src/ast_nodes/member_expression.rs b/rust/parse_ast/src/ast_nodes/member_expression.rs index 8f9ed91244c..f0eb33a684e 100644 --- a/rust/parse_ast/src/ast_nodes/member_expression.rs +++ b/rust/parse_ast/src/ast_nodes/member_expression.rs @@ -1,18 +1,18 @@ use swc_common::Span; use swc_ecma_ast::{ - ComputedPropName, Expr, IdentName, MemberExpr, MemberProp, PrivateName, Super, SuperProp, - SuperPropExpr, + ComputedPropName, Expr, IdentName, MemberExpr, MemberProp, PrivateName, Super, SuperProp, + SuperPropExpr, }; use crate::convert_ast::converter::ast_constants::{ - MEMBER_EXPRESSION_OBJECT_OFFSET, MEMBER_EXPRESSION_PROPERTY_OFFSET, - MEMBER_EXPRESSION_RESERVED_BYTES, TYPE_MEMBER_EXPRESSION, + MEMBER_EXPRESSION_OBJECT_OFFSET, MEMBER_EXPRESSION_PROPERTY_OFFSET, + MEMBER_EXPRESSION_RESERVED_BYTES, TYPE_MEMBER_EXPRESSION, }; use crate::convert_ast::converter::AstConverter; use crate::store_member_expression_flags; impl<'a> AstConverter<'a> { - pub fn store_member_expression( + pub(crate) fn store_member_expression( &mut self, span: &Span, is_optional: bool, @@ -63,7 +63,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, span); } - pub fn convert_member_expression( + pub(crate) fn convert_member_expression( &mut self, member_expression: &MemberExpr, is_optional: bool, @@ -82,7 +82,7 @@ impl<'a> AstConverter<'a> { ); } - pub fn convert_super_property(&mut self, super_property: &SuperPropExpr) { + pub(crate) fn convert_super_property(&mut self, super_property: &SuperPropExpr) { self.store_member_expression( &super_property.span, false, @@ -98,13 +98,13 @@ impl<'a> AstConverter<'a> { } } -pub enum MemberOrSuperProp<'a> { +pub(crate) enum MemberOrSuperProp<'a> { Identifier(&'a IdentName), PrivateName(&'a PrivateName), Computed(&'a ComputedPropName), } -pub enum ExpressionOrSuper<'a> { +pub(crate) enum ExpressionOrSuper<'a> { Expression(&'a Expr), Super(&'a Super), } diff --git a/rust/parse_ast/src/ast_nodes/meta_property.rs b/rust/parse_ast/src/ast_nodes/meta_property.rs index 209886668bd..5028e01c4e8 100644 --- a/rust/parse_ast/src/ast_nodes/meta_property.rs +++ b/rust/parse_ast/src/ast_nodes/meta_property.rs @@ -1,13 +1,13 @@ use swc_ecma_ast::{MetaPropExpr, MetaPropKind}; use crate::convert_ast::converter::ast_constants::{ - META_PROPERTY_META_OFFSET, META_PROPERTY_PROPERTY_OFFSET, META_PROPERTY_RESERVED_BYTES, - TYPE_META_PROPERTY, + META_PROPERTY_META_OFFSET, META_PROPERTY_PROPERTY_OFFSET, META_PROPERTY_RESERVED_BYTES, + TYPE_META_PROPERTY, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_meta_property(&mut self, meta_property_expression: &MetaPropExpr) { + pub(crate) fn store_meta_property(&mut self, meta_property_expression: &MetaPropExpr) { let end_position = self.add_type_and_start( &TYPE_META_PROPERTY, &meta_property_expression.span, diff --git a/rust/parse_ast/src/ast_nodes/method_definition.rs b/rust/parse_ast/src/ast_nodes/method_definition.rs index e7fd91e2ff8..c17eed5a613 100644 --- a/rust/parse_ast/src/ast_nodes/method_definition.rs +++ b/rust/parse_ast/src/ast_nodes/method_definition.rs @@ -10,14 +10,14 @@ use crate::convert_ast::converter::ast_constants::{ METHOD_DEFINITION_RESERVED_BYTES, METHOD_DEFINITION_VALUE_OFFSET, TYPE_FUNCTION_EXPRESSION, TYPE_METHOD_DEFINITION, }; +use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ STRING_CONSTRUCTOR, STRING_GET, STRING_METHOD, STRING_SET, }; -use crate::convert_ast::converter::AstConverter; use crate::store_method_definition_flags; impl<'a> AstConverter<'a> { - pub fn store_method_definition( + pub(crate) fn store_method_definition( &mut self, span: &Span, kind: &MethodKind, @@ -81,7 +81,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, span); } - pub fn convert_constructor(&mut self, constructor: &Constructor) { + pub(crate) fn convert_constructor(&mut self, constructor: &Constructor) { let end_position = self.add_type_and_start( &TYPE_METHOD_DEFINITION, &constructor.span, @@ -130,7 +130,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &constructor.span); } - pub fn convert_method(&mut self, method: &ClassMethod) { + pub(crate) fn convert_method(&mut self, method: &ClassMethod) { self.store_method_definition( &method.span, &method.kind, @@ -141,7 +141,7 @@ impl<'a> AstConverter<'a> { ); } - pub fn convert_private_method(&mut self, private_method: &PrivateMethod) { + pub(crate) fn convert_private_method(&mut self, private_method: &PrivateMethod) { self.store_method_definition( &private_method.span, &private_method.kind, @@ -153,7 +153,7 @@ impl<'a> AstConverter<'a> { } } -pub enum PropOrPrivateName<'a> { +pub(crate) enum PropOrPrivateName<'a> { PropName(&'a PropName), PrivateName(&'a PrivateName), } diff --git a/rust/parse_ast/src/ast_nodes/mod.rs b/rust/parse_ast/src/ast_nodes/mod.rs index 6460225cc11..ab7560659a2 100644 --- a/rust/parse_ast/src/ast_nodes/mod.rs +++ b/rust/parse_ast/src/ast_nodes/mod.rs @@ -1,96 +1,96 @@ -pub mod array_expression; -pub mod array_pattern; -pub mod arrow_function_expression; -pub mod assignment_expression; -pub mod assignment_pattern; -pub mod await_expression; -pub mod binary_expression; -pub mod block_statement; -pub mod break_statement; -pub mod call_expression; -pub mod catch_clause; -pub mod chain_expression; -pub mod class_body; -pub mod class_declaration; -pub mod class_expression; -pub mod conditional_expression; -pub mod continue_statement; -pub mod debugger_statement; -pub mod decorator; -pub mod directive; -pub mod do_while_statement; -pub mod empty_statement; -pub mod export_all_declaration; -pub mod export_default_declaration; -pub mod export_named_declaration; -pub mod export_specifier; -pub mod expression_statement; -pub mod for_in_statement; -pub mod for_of_statement; -pub mod for_statement; -pub mod function_declaration; -pub mod function_expression; -pub mod identifier; -pub mod if_statement; -pub mod import_attribute; -pub mod import_declaration; -pub mod import_default_specifier; -pub mod import_expression; -pub mod import_namespace_specifier; -pub mod import_specifier; -pub mod jsx_attribute; -pub mod jsx_closing_element; -pub mod jsx_closing_fragment; -pub mod jsx_element; -pub mod jsx_empty_expression; -pub mod jsx_expression_container; -pub mod jsx_fragment; -pub mod jsx_identifier; -pub mod jsx_member_expression; -pub mod jsx_namespaced_name; -pub mod jsx_opening_element; -pub mod jsx_opening_fragment; -pub mod jsx_spread_attribute; -pub mod jsx_spread_child; -pub mod jsx_text; -pub mod labeled_statement; -pub mod literal_big_int; -pub mod literal_boolean; -pub mod literal_null; -pub mod literal_number; -pub mod literal_reg_exp; -pub mod literal_string; -pub mod logical_expression; -pub mod member_expression; -pub mod meta_property; -pub mod method_definition; -pub mod new_expression; -pub mod object_expression; -pub mod object_pattern; -pub mod panic_error; -pub mod parse_error; -pub mod private_identifier; -pub mod program; -pub mod property; -pub mod property_definition; -pub mod rest_element; -pub mod return_statement; -pub mod sequence_expression; -pub mod shared; -pub mod spread_element; -pub mod static_block; -pub mod super_element; -pub mod switch_case; -pub mod switch_statement; -pub mod tagged_template_expression; -pub mod template_element; -pub mod template_literal; -pub mod this_expression; -pub mod throw_statement; -pub mod try_statement; -pub mod unary_expression; -pub mod update_expression; -pub mod variable_declaration; -pub mod variable_declarator; -pub mod while_statement; -pub mod yield_expression; +pub(crate) mod array_expression; +pub(crate) mod array_pattern; +pub(crate) mod arrow_function_expression; +pub(crate) mod assignment_expression; +pub(crate) mod assignment_pattern; +pub(crate) mod await_expression; +pub(crate) mod binary_expression; +pub(crate) mod block_statement; +pub(crate) mod break_statement; +pub(crate) mod call_expression; +pub(crate) mod catch_clause; +pub(crate) mod chain_expression; +pub(crate) mod class_body; +pub(crate) mod class_declaration; +pub(crate) mod class_expression; +pub(crate) mod conditional_expression; +pub(crate) mod continue_statement; +pub(crate) mod debugger_statement; +pub(crate) mod decorator; +pub(crate) mod directive; +pub(crate) mod do_while_statement; +pub(crate) mod empty_statement; +pub(crate) mod export_all_declaration; +pub(crate) mod export_default_declaration; +pub(crate) mod export_named_declaration; +pub(crate) mod export_specifier; +pub(crate) mod expression_statement; +pub(crate) mod for_in_statement; +pub(crate) mod for_of_statement; +pub(crate) mod for_statement; +pub(crate) mod function_declaration; +pub(crate) mod function_expression; +pub(crate) mod identifier; +pub(crate) mod if_statement; +pub(crate) mod import_attribute; +pub(crate) mod import_declaration; +pub(crate) mod import_default_specifier; +pub(crate) mod import_expression; +pub(crate) mod import_namespace_specifier; +pub(crate) mod import_specifier; +pub(crate) mod jsx_attribute; +pub(crate) mod jsx_closing_element; +pub(crate) mod jsx_closing_fragment; +pub(crate) mod jsx_element; +pub(crate) mod jsx_empty_expression; +pub(crate) mod jsx_expression_container; +pub(crate) mod jsx_fragment; +pub(crate) mod jsx_identifier; +pub(crate) mod jsx_member_expression; +pub(crate) mod jsx_namespaced_name; +pub(crate) mod jsx_opening_element; +pub(crate) mod jsx_opening_fragment; +pub(crate) mod jsx_spread_attribute; +pub(crate) mod jsx_spread_child; +pub(crate) mod jsx_text; +pub(crate) mod labeled_statement; +pub(crate) mod literal_big_int; +pub(crate) mod literal_boolean; +pub(crate) mod literal_null; +pub(crate) mod literal_number; +pub(crate) mod literal_reg_exp; +pub(crate) mod literal_string; +pub(crate) mod logical_expression; +pub(crate) mod member_expression; +pub(crate) mod meta_property; +pub(crate) mod method_definition; +pub(crate) mod new_expression; +pub(crate) mod object_expression; +pub(crate) mod object_pattern; +pub(crate) mod panic_error; +pub(crate) mod parse_error; +pub(crate) mod private_identifier; +pub(crate) mod program; +pub(crate) mod property; +pub(crate) mod property_definition; +pub(crate) mod rest_element; +pub(crate) mod return_statement; +pub(crate) mod sequence_expression; +pub(crate) mod shared; +pub(crate) mod spread_element; +pub(crate) mod static_block; +pub(crate) mod super_element; +pub(crate) mod switch_case; +pub(crate) mod switch_statement; +pub(crate) mod tagged_template_expression; +pub(crate) mod template_element; +pub(crate) mod template_literal; +pub(crate) mod this_expression; +pub(crate) mod throw_statement; +pub(crate) mod try_statement; +pub(crate) mod unary_expression; +pub(crate) mod update_expression; +pub(crate) mod variable_declaration; +pub(crate) mod variable_declarator; +pub(crate) mod while_statement; +pub(crate) mod yield_expression; diff --git a/rust/parse_ast/src/ast_nodes/new_expression.rs b/rust/parse_ast/src/ast_nodes/new_expression.rs index 9b16a35bfe1..00a5629ff77 100644 --- a/rust/parse_ast/src/ast_nodes/new_expression.rs +++ b/rust/parse_ast/src/ast_nodes/new_expression.rs @@ -1,14 +1,14 @@ use swc_ecma_ast::NewExpr; use crate::convert_ast::annotations::AnnotationKind; +use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ - NEW_EXPRESSION_ANNOTATIONS_OFFSET, NEW_EXPRESSION_ARGUMENTS_OFFSET, NEW_EXPRESSION_CALLEE_OFFSET, - NEW_EXPRESSION_RESERVED_BYTES, TYPE_NEW_EXPRESSION, + NEW_EXPRESSION_ANNOTATIONS_OFFSET, NEW_EXPRESSION_ARGUMENTS_OFFSET, NEW_EXPRESSION_CALLEE_OFFSET, + NEW_EXPRESSION_RESERVED_BYTES, TYPE_NEW_EXPRESSION, }; -use crate::convert_ast::converter::{convert_annotation, AstConverter}; impl<'a> AstConverter<'a> { - pub fn store_new_expression(&mut self, new_expression: &NewExpr) { + pub(crate) fn store_new_expression(&mut self, new_expression: &NewExpr) { let end_position = self.add_type_and_start( &TYPE_NEW_EXPRESSION, &new_expression.span, diff --git a/rust/parse_ast/src/ast_nodes/object_expression.rs b/rust/parse_ast/src/ast_nodes/object_expression.rs index 72e07f702fc..647ac19be59 100644 --- a/rust/parse_ast/src/ast_nodes/object_expression.rs +++ b/rust/parse_ast/src/ast_nodes/object_expression.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_object_expression; impl<'a> AstConverter<'a> { - pub fn store_object_expression(&mut self, object_literal: &ObjectLit) { + pub(crate) fn store_object_expression(&mut self, object_literal: &ObjectLit) { store_object_expression!( self, span => &object_literal.span, diff --git a/rust/parse_ast/src/ast_nodes/object_pattern.rs b/rust/parse_ast/src/ast_nodes/object_pattern.rs index 22a958bd90d..16b3dc1ff7f 100644 --- a/rust/parse_ast/src/ast_nodes/object_pattern.rs +++ b/rust/parse_ast/src/ast_nodes/object_pattern.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_object_pattern; impl<'a> AstConverter<'a> { - pub fn store_object_pattern(&mut self, object_pattern: &ObjectPat) { + pub(crate) fn store_object_pattern(&mut self, object_pattern: &ObjectPat) { store_object_pattern!( self, span => &object_pattern.span, diff --git a/rust/parse_ast/src/ast_nodes/panic_error.rs b/rust/parse_ast/src/ast_nodes/panic_error.rs index d53ae8bf563..e01b606763d 100644 --- a/rust/parse_ast/src/ast_nodes/panic_error.rs +++ b/rust/parse_ast/src/ast_nodes/panic_error.rs @@ -1,9 +1,9 @@ +use crate::convert_ast::converter::{convert_string, update_reference_position}; use crate::convert_ast::converter::ast_constants::{ - PANIC_ERROR_MESSAGE_OFFSET, PANIC_ERROR_RESERVED_BYTES, TYPE_PANIC_ERROR, + PANIC_ERROR_MESSAGE_OFFSET, PANIC_ERROR_RESERVED_BYTES, TYPE_PANIC_ERROR, }; -use crate::convert_ast::converter::{convert_string, update_reference_position}; -pub fn get_panic_error_buffer(message: &str) -> Vec { +pub(crate) fn get_panic_error_buffer(message: &str) -> Vec { // type let mut buffer = TYPE_PANIC_ERROR.to_vec(); // reserve for start and end even though they are unused diff --git a/rust/parse_ast/src/ast_nodes/parse_error.rs b/rust/parse_ast/src/ast_nodes/parse_error.rs index 440624a7707..b17c5c2c420 100644 --- a/rust/parse_ast/src/ast_nodes/parse_error.rs +++ b/rust/parse_ast/src/ast_nodes/parse_error.rs @@ -1,9 +1,9 @@ use crate::convert_ast::converter::ast_constants::{ - PARSE_ERROR_MESSAGE_OFFSET, PARSE_ERROR_RESERVED_BYTES, TYPE_PARSE_ERROR, + PARSE_ERROR_MESSAGE_OFFSET, PARSE_ERROR_RESERVED_BYTES, TYPE_PARSE_ERROR, }; use crate::convert_ast::converter::update_reference_position; -pub fn get_parse_error_buffer(error_buffer: &[u8], utf_16_pos: &u32) -> Vec { +pub(crate) fn get_parse_error_buffer(error_buffer: &[u8], utf_16_pos: &u32) -> Vec { // type let mut buffer = TYPE_PARSE_ERROR.to_vec(); // start diff --git a/rust/parse_ast/src/ast_nodes/private_identifier.rs b/rust/parse_ast/src/ast_nodes/private_identifier.rs index d1797c9a7c1..2ae38cd4d87 100644 --- a/rust/parse_ast/src/ast_nodes/private_identifier.rs +++ b/rust/parse_ast/src/ast_nodes/private_identifier.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_private_identifier; impl<'a> AstConverter<'a> { - pub fn store_private_identifier(&mut self, private_name: &PrivateName) { + pub(crate) fn store_private_identifier(&mut self, private_name: &PrivateName) { store_private_identifier!( self, span => &private_name.span, diff --git a/rust/parse_ast/src/ast_nodes/program.rs b/rust/parse_ast/src/ast_nodes/program.rs index 60c34485cba..001c8e67344 100644 --- a/rust/parse_ast/src/ast_nodes/program.rs +++ b/rust/parse_ast/src/ast_nodes/program.rs @@ -1,12 +1,12 @@ use swc_ecma_ast::{Expr, Lit, ModuleItem, Program, Stmt}; +use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ - PROGRAM_BODY_OFFSET, PROGRAM_INVALID_ANNOTATIONS_OFFSET, PROGRAM_RESERVED_BYTES, TYPE_PROGRAM, + PROGRAM_BODY_OFFSET, PROGRAM_INVALID_ANNOTATIONS_OFFSET, PROGRAM_RESERVED_BYTES, TYPE_PROGRAM, }; -use crate::convert_ast::converter::{convert_annotation, AstConverter}; impl<'a> AstConverter<'a> { - pub fn store_program(&mut self, body: ModuleItemsOrStatements) { + pub(crate) fn store_program(&mut self, body: ModuleItemsOrStatements) { let end_position = self.add_type_and_explicit_start(&TYPE_PROGRAM, 0u32, PROGRAM_RESERVED_BYTES); // body @@ -71,7 +71,7 @@ impl<'a> AstConverter<'a> { } } - pub fn convert_program(&mut self, node: &Program) { + pub(crate) fn convert_program(&mut self, node: &Program) { match node { Program::Module(module) => { self.store_program(ModuleItemsOrStatements::ModuleItems(&module.body)); @@ -83,7 +83,7 @@ impl<'a> AstConverter<'a> { } } -pub enum ModuleItemsOrStatements<'a> { +pub(crate) enum ModuleItemsOrStatements<'a> { ModuleItems(&'a Vec), Statements(&'a Vec), } diff --git a/rust/parse_ast/src/ast_nodes/property.rs b/rust/parse_ast/src/ast_nodes/property.rs index f2c9b866d75..883771b20e1 100644 --- a/rust/parse_ast/src/ast_nodes/property.rs +++ b/rust/parse_ast/src/ast_nodes/property.rs @@ -10,12 +10,12 @@ use crate::convert_ast::converter::ast_constants::{ PROPERTY_KEY_OFFSET, PROPERTY_KIND_OFFSET, PROPERTY_RESERVED_BYTES, PROPERTY_VALUE_OFFSET, TYPE_FUNCTION_EXPRESSION, TYPE_PROPERTY, }; -use crate::convert_ast::converter::string_constants::{STRING_GET, STRING_INIT, STRING_SET}; use crate::convert_ast::converter::AstConverter; +use crate::convert_ast::converter::string_constants::{STRING_GET, STRING_INIT, STRING_SET}; use crate::store_property_flags; impl<'a> AstConverter<'a> { - pub fn convert_property(&mut self, property: &Prop) { + pub(crate) fn convert_property(&mut self, property: &Prop) { match property { Prop::Getter(getter_property) => self.convert_getter_property(getter_property), Prop::KeyValue(key_value_property) => self.convert_key_value_property(key_value_property), @@ -26,7 +26,7 @@ impl<'a> AstConverter<'a> { } } - pub fn convert_assignment_pattern_property( + pub(crate) fn convert_assignment_pattern_property( &mut self, assignment_pattern_property: &AssignPatProp, ) { @@ -37,7 +37,7 @@ impl<'a> AstConverter<'a> { ); } - pub fn convert_key_value_pattern_property( + pub(crate) fn convert_key_value_pattern_property( &mut self, key_value_pattern_property: &KeyValuePatProp, ) { @@ -242,7 +242,7 @@ impl<'a> AstConverter<'a> { } #[derive(Spanned)] -pub enum PatternOrExpression<'a> { +pub(crate) enum PatternOrExpression<'a> { Pattern(&'a Pat), Expression(&'a Expr), } diff --git a/rust/parse_ast/src/ast_nodes/property_definition.rs b/rust/parse_ast/src/ast_nodes/property_definition.rs index 24d8c89d397..33c310c44f0 100644 --- a/rust/parse_ast/src/ast_nodes/property_definition.rs +++ b/rust/parse_ast/src/ast_nodes/property_definition.rs @@ -3,14 +3,14 @@ use swc_ecma_ast::{ClassProp, Decorator, Expr, PrivateProp, PropName}; use crate::ast_nodes::method_definition::PropOrPrivateName; use crate::convert_ast::converter::ast_constants::{ - PROPERTY_DEFINITION_DECORATORS_OFFSET, PROPERTY_DEFINITION_KEY_OFFSET, - PROPERTY_DEFINITION_RESERVED_BYTES, PROPERTY_DEFINITION_VALUE_OFFSET, TYPE_PROPERTY_DEFINITION, + PROPERTY_DEFINITION_DECORATORS_OFFSET, PROPERTY_DEFINITION_KEY_OFFSET, + PROPERTY_DEFINITION_RESERVED_BYTES, PROPERTY_DEFINITION_VALUE_OFFSET, TYPE_PROPERTY_DEFINITION, }; use crate::convert_ast::converter::AstConverter; use crate::store_property_definition_flags; impl<'a> AstConverter<'a> { - pub fn store_property_definition( + pub(crate) fn store_property_definition( &mut self, span: &Span, is_computed: bool, @@ -53,7 +53,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, span); } - pub fn convert_class_property(&mut self, class_property: &ClassProp) { + pub(crate) fn convert_class_property(&mut self, class_property: &ClassProp) { self.store_property_definition( &class_property.span, matches!(&class_property.key, PropName::Computed(_)), @@ -64,7 +64,7 @@ impl<'a> AstConverter<'a> { ); } - pub fn convert_private_property(&mut self, private_property: &PrivateProp) { + pub(crate) fn convert_private_property(&mut self, private_property: &PrivateProp) { self.store_property_definition( &private_property.span, false, diff --git a/rust/parse_ast/src/ast_nodes/rest_element.rs b/rust/parse_ast/src/ast_nodes/rest_element.rs index 2bf6d1fe6be..31124013a26 100644 --- a/rust/parse_ast/src/ast_nodes/rest_element.rs +++ b/rust/parse_ast/src/ast_nodes/rest_element.rs @@ -1,12 +1,12 @@ use swc_ecma_ast::RestPat; use crate::convert_ast::converter::ast_constants::{ - REST_ELEMENT_ARGUMENT_OFFSET, REST_ELEMENT_RESERVED_BYTES, TYPE_REST_ELEMENT, + REST_ELEMENT_ARGUMENT_OFFSET, REST_ELEMENT_RESERVED_BYTES, TYPE_REST_ELEMENT, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_rest_element(&mut self, rest_pattern: &RestPat) { + pub(crate) fn store_rest_element(&mut self, rest_pattern: &RestPat) { let end_position = self.add_type_and_start( &TYPE_REST_ELEMENT, &rest_pattern.dot3_token, diff --git a/rust/parse_ast/src/ast_nodes/return_statement.rs b/rust/parse_ast/src/ast_nodes/return_statement.rs index 5a0870bd564..0e41a910b77 100644 --- a/rust/parse_ast/src/ast_nodes/return_statement.rs +++ b/rust/parse_ast/src/ast_nodes/return_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_return_statement; impl<'a> AstConverter<'a> { - pub fn store_return_statement(&mut self, return_statement: &ReturnStmt) { + pub(crate) fn store_return_statement(&mut self, return_statement: &ReturnStmt) { store_return_statement!( self, span => return_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/sequence_expression.rs b/rust/parse_ast/src/ast_nodes/sequence_expression.rs index fa69c151e4d..f179cdbf36e 100644 --- a/rust/parse_ast/src/ast_nodes/sequence_expression.rs +++ b/rust/parse_ast/src/ast_nodes/sequence_expression.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_sequence_expression; impl<'a> AstConverter<'a> { - pub fn store_sequence_expression(&mut self, sequence_expression: &SeqExpr) { + pub(crate) fn store_sequence_expression(&mut self, sequence_expression: &SeqExpr) { store_sequence_expression!( self, span => &sequence_expression.span, diff --git a/rust/parse_ast/src/ast_nodes/shared/class_node.rs b/rust/parse_ast/src/ast_nodes/shared/class_node.rs index 67d6fa32bd3..83abd0d7148 100644 --- a/rust/parse_ast/src/ast_nodes/shared/class_node.rs +++ b/rust/parse_ast/src/ast_nodes/shared/class_node.rs @@ -3,13 +3,13 @@ use swc_ecma_ast::{Class, Ident}; use crate::convert_ast::converter::analyze_code::find_first_occurrence_outside_comment; use crate::convert_ast::converter::ast_constants::{ - CLASS_DECLARATION_BODY_OFFSET, CLASS_DECLARATION_DECORATORS_OFFSET, CLASS_DECLARATION_ID_OFFSET, - CLASS_DECLARATION_RESERVED_BYTES, CLASS_DECLARATION_SUPER_CLASS_OFFSET, + CLASS_DECLARATION_BODY_OFFSET, CLASS_DECLARATION_DECORATORS_OFFSET, CLASS_DECLARATION_ID_OFFSET, + CLASS_DECLARATION_RESERVED_BYTES, CLASS_DECLARATION_SUPER_CLASS_OFFSET, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_class_node( + pub(crate) fn store_class_node( &mut self, node_type: &[u8; 4], identifier: Option<&Ident>, diff --git a/rust/parse_ast/src/ast_nodes/shared/function_node.rs b/rust/parse_ast/src/ast_nodes/shared/function_node.rs index 34d868e5f0e..739597134d5 100644 --- a/rust/parse_ast/src/ast_nodes/shared/function_node.rs +++ b/rust/parse_ast/src/ast_nodes/shared/function_node.rs @@ -1,12 +1,12 @@ use swc_ecma_ast::{BlockStmt, Function, Ident, Pat}; use crate::convert_ast::annotations::AnnotationKind; +use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ FUNCTION_DECLARATION_ANNOTATIONS_OFFSET, FUNCTION_DECLARATION_BODY_OFFSET, FUNCTION_DECLARATION_ID_OFFSET, FUNCTION_DECLARATION_PARAMS_OFFSET, FUNCTION_DECLARATION_RESERVED_BYTES, }; -use crate::convert_ast::converter::{convert_annotation, AstConverter}; use crate::store_function_declaration_flags; impl<'a> AstConverter<'a> { @@ -31,7 +31,7 @@ impl<'a> AstConverter<'a> { } #[allow(clippy::too_many_arguments)] - pub fn store_function_node( + pub(crate) fn store_function_node( &mut self, node_type: &[u8; 4], start: u32, diff --git a/rust/parse_ast/src/ast_nodes/spread_element.rs b/rust/parse_ast/src/ast_nodes/spread_element.rs index 8bd63a7bbc3..0a6b9dfbd96 100644 --- a/rust/parse_ast/src/ast_nodes/spread_element.rs +++ b/rust/parse_ast/src/ast_nodes/spread_element.rs @@ -7,7 +7,7 @@ use crate::convert_ast::converter::ast_constants::{ use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_spread_element(&mut self, dot_span: &Span, argument: &Expr) { + pub(crate) fn store_spread_element(&mut self, dot_span: &Span, argument: &Expr) { let end_position = self.add_type_and_start( &TYPE_SPREAD_ELEMENT, dot_span, @@ -21,7 +21,7 @@ impl<'a> AstConverter<'a> { self.add_end(end_position, &argument.span()); } - pub fn convert_spread_element(&mut self, spread_element: &SpreadElement) { + pub(crate) fn convert_spread_element(&mut self, spread_element: &SpreadElement) { self.store_spread_element(&spread_element.dot3_token, &spread_element.expr); } } diff --git a/rust/parse_ast/src/ast_nodes/static_block.rs b/rust/parse_ast/src/ast_nodes/static_block.rs index 43d858cc3b7..4b0e7d46105 100644 --- a/rust/parse_ast/src/ast_nodes/static_block.rs +++ b/rust/parse_ast/src/ast_nodes/static_block.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_static_block; impl<'a> AstConverter<'a> { - pub fn store_static_block(&mut self, static_block: &StaticBlock) { + pub(crate) fn store_static_block(&mut self, static_block: &StaticBlock) { store_static_block!( self, span => &static_block.span, diff --git a/rust/parse_ast/src/ast_nodes/super_element.rs b/rust/parse_ast/src/ast_nodes/super_element.rs index cb5df082095..1ca9c66767e 100644 --- a/rust/parse_ast/src/ast_nodes/super_element.rs +++ b/rust/parse_ast/src/ast_nodes/super_element.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_super_element; impl<'a> AstConverter<'a> { - pub fn store_super_element(&mut self, super_token: &Super) { + pub(crate) fn store_super_element(&mut self, super_token: &Super) { store_super_element!( self, span => &super_token.span diff --git a/rust/parse_ast/src/ast_nodes/switch_case.rs b/rust/parse_ast/src/ast_nodes/switch_case.rs index e1a27867466..3cd92797cab 100644 --- a/rust/parse_ast/src/ast_nodes/switch_case.rs +++ b/rust/parse_ast/src/ast_nodes/switch_case.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_switch_case; impl<'a> AstConverter<'a> { - pub fn store_switch_case(&mut self, switch_case: &SwitchCase) { + pub(crate) fn store_switch_case(&mut self, switch_case: &SwitchCase) { store_switch_case!( self, span => &switch_case.span, diff --git a/rust/parse_ast/src/ast_nodes/switch_statement.rs b/rust/parse_ast/src/ast_nodes/switch_statement.rs index 2c6ba5684a4..3dd18303d15 100644 --- a/rust/parse_ast/src/ast_nodes/switch_statement.rs +++ b/rust/parse_ast/src/ast_nodes/switch_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_switch_statement; impl<'a> AstConverter<'a> { - pub fn store_switch_statement(&mut self, switch_statement: &SwitchStmt) { + pub(crate) fn store_switch_statement(&mut self, switch_statement: &SwitchStmt) { store_switch_statement!( self, span => &switch_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/tagged_template_expression.rs b/rust/parse_ast/src/ast_nodes/tagged_template_expression.rs index c7cdcacfae1..ac7fdbc01ef 100644 --- a/rust/parse_ast/src/ast_nodes/tagged_template_expression.rs +++ b/rust/parse_ast/src/ast_nodes/tagged_template_expression.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_tagged_template_expression; impl<'a> AstConverter<'a> { - pub fn store_tagged_template_expression(&mut self, tagged_template: &TaggedTpl) { + pub(crate) fn store_tagged_template_expression(&mut self, tagged_template: &TaggedTpl) { store_tagged_template_expression!( self, span => &tagged_template.span, diff --git a/rust/parse_ast/src/ast_nodes/template_element.rs b/rust/parse_ast/src/ast_nodes/template_element.rs index 3b9d385fb60..23346d9388d 100644 --- a/rust/parse_ast/src/ast_nodes/template_element.rs +++ b/rust/parse_ast/src/ast_nodes/template_element.rs @@ -1,10 +1,10 @@ use swc_ecma_ast::TplElement; -use crate::convert_ast::converter::AstConverter; use crate::{store_template_element, store_template_element_flags}; +use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_template_element(&mut self, template_element: &TplElement) { + pub(crate) fn store_template_element(&mut self, template_element: &TplElement) { store_template_element!( self, span => &template_element.span, diff --git a/rust/parse_ast/src/ast_nodes/template_literal.rs b/rust/parse_ast/src/ast_nodes/template_literal.rs index 6548615a8fd..39c1f83d85b 100644 --- a/rust/parse_ast/src/ast_nodes/template_literal.rs +++ b/rust/parse_ast/src/ast_nodes/template_literal.rs @@ -1,13 +1,13 @@ use swc_ecma_ast::Tpl; use crate::convert_ast::converter::ast_constants::{ - TEMPLATE_LITERAL_EXPRESSIONS_OFFSET, TEMPLATE_LITERAL_QUASIS_OFFSET, - TEMPLATE_LITERAL_RESERVED_BYTES, TYPE_TEMPLATE_LITERAL, + TEMPLATE_LITERAL_EXPRESSIONS_OFFSET, TEMPLATE_LITERAL_QUASIS_OFFSET, + TEMPLATE_LITERAL_RESERVED_BYTES, TYPE_TEMPLATE_LITERAL, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_template_literal(&mut self, template_literal: &Tpl) { + pub(crate) fn store_template_literal(&mut self, template_literal: &Tpl) { let end_position = self.add_type_and_start( &TYPE_TEMPLATE_LITERAL, &template_literal.span, diff --git a/rust/parse_ast/src/ast_nodes/this_expression.rs b/rust/parse_ast/src/ast_nodes/this_expression.rs index 37c0a8b8690..0e65f17bcb4 100644 --- a/rust/parse_ast/src/ast_nodes/this_expression.rs +++ b/rust/parse_ast/src/ast_nodes/this_expression.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_this_expression; impl<'a> AstConverter<'a> { - pub fn store_this_expression(&mut self, this_expression: &ThisExpr) { + pub(crate) fn store_this_expression(&mut self, this_expression: &ThisExpr) { store_this_expression!(self, span => this_expression.span); } } diff --git a/rust/parse_ast/src/ast_nodes/throw_statement.rs b/rust/parse_ast/src/ast_nodes/throw_statement.rs index 32fe923975a..0d154da6839 100644 --- a/rust/parse_ast/src/ast_nodes/throw_statement.rs +++ b/rust/parse_ast/src/ast_nodes/throw_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_throw_statement; impl<'a> AstConverter<'a> { - pub fn store_throw_statement(&mut self, throw_statement: &ThrowStmt) { + pub(crate) fn store_throw_statement(&mut self, throw_statement: &ThrowStmt) { store_throw_statement!( self, span => &throw_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/try_statement.rs b/rust/parse_ast/src/ast_nodes/try_statement.rs index a5985f28541..e49cae9288e 100644 --- a/rust/parse_ast/src/ast_nodes/try_statement.rs +++ b/rust/parse_ast/src/ast_nodes/try_statement.rs @@ -1,13 +1,13 @@ use swc_ecma_ast::TryStmt; use crate::convert_ast::converter::ast_constants::{ - TRY_STATEMENT_BLOCK_OFFSET, TRY_STATEMENT_FINALIZER_OFFSET, TRY_STATEMENT_HANDLER_OFFSET, - TRY_STATEMENT_RESERVED_BYTES, TYPE_TRY_STATEMENT, + TRY_STATEMENT_BLOCK_OFFSET, TRY_STATEMENT_FINALIZER_OFFSET, TRY_STATEMENT_HANDLER_OFFSET, + TRY_STATEMENT_RESERVED_BYTES, TYPE_TRY_STATEMENT, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_try_statement(&mut self, try_statement: &TryStmt) { + pub(crate) fn store_try_statement(&mut self, try_statement: &TryStmt) { let end_position = self.add_type_and_start( &TYPE_TRY_STATEMENT, &try_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/unary_expression.rs b/rust/parse_ast/src/ast_nodes/unary_expression.rs index 29141028576..b0c01849286 100644 --- a/rust/parse_ast/src/ast_nodes/unary_expression.rs +++ b/rust/parse_ast/src/ast_nodes/unary_expression.rs @@ -1,13 +1,13 @@ use swc_ecma_ast::{UnaryExpr, UnaryOp}; +use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ - STRING_BANG, STRING_DELETE, STRING_MINUS, STRING_PLUS, STRING_TILDE, STRING_TYPEOF, STRING_VOID, + STRING_BANG, STRING_DELETE, STRING_MINUS, STRING_PLUS, STRING_TILDE, STRING_TYPEOF, STRING_VOID, }; -use crate::convert_ast::converter::AstConverter; use crate::store_unary_expression; impl<'a> AstConverter<'a> { - pub fn store_unary_expression(&mut self, unary_expression: &UnaryExpr) { + pub(crate) fn store_unary_expression(&mut self, unary_expression: &UnaryExpr) { store_unary_expression!( self, span => &unary_expression.span, diff --git a/rust/parse_ast/src/ast_nodes/update_expression.rs b/rust/parse_ast/src/ast_nodes/update_expression.rs index cbf59a3f5cb..5886609c8bd 100644 --- a/rust/parse_ast/src/ast_nodes/update_expression.rs +++ b/rust/parse_ast/src/ast_nodes/update_expression.rs @@ -5,7 +5,7 @@ use crate::convert_ast::converter::AstConverter; use crate::{store_update_expression, store_update_expression_flags}; impl<'a> AstConverter<'a> { - pub fn store_update_expression(&mut self, update_expression: &UpdateExpr) { + pub(crate) fn store_update_expression(&mut self, update_expression: &UpdateExpr) { store_update_expression!( self, span => &update_expression.span, diff --git a/rust/parse_ast/src/ast_nodes/variable_declaration.rs b/rust/parse_ast/src/ast_nodes/variable_declaration.rs index 65108c3313a..a0fe597055c 100644 --- a/rust/parse_ast/src/ast_nodes/variable_declaration.rs +++ b/rust/parse_ast/src/ast_nodes/variable_declaration.rs @@ -1,17 +1,17 @@ use swc_common::Span; -use swc_ecma_ast::{UsingDecl, VarDecl, VarDeclKind, VarDeclarator}; +use swc_ecma_ast::{UsingDecl, VarDecl, VarDeclarator, VarDeclKind}; use crate::convert_ast::converter::ast_constants::{ - TYPE_VARIABLE_DECLARATION, VARIABLE_DECLARATION_DECLARATIONS_OFFSET, - VARIABLE_DECLARATION_KIND_OFFSET, VARIABLE_DECLARATION_RESERVED_BYTES, + TYPE_VARIABLE_DECLARATION, VARIABLE_DECLARATION_DECLARATIONS_OFFSET, + VARIABLE_DECLARATION_KIND_OFFSET, VARIABLE_DECLARATION_RESERVED_BYTES, }; +use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ - STRING_AWAIT_USING, STRING_CONST, STRING_LET, STRING_USING, STRING_VAR, + STRING_AWAIT_USING, STRING_CONST, STRING_LET, STRING_USING, STRING_VAR, }; -use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_variable_declaration(&mut self, variable_declaration: &VariableDeclaration) { + pub(crate) fn store_variable_declaration(&mut self, variable_declaration: &VariableDeclaration) { let (kind, span, decls): (&[u8; 4], Span, &Vec) = match variable_declaration { VariableDeclaration::Var(value) => ( match value.kind { @@ -55,7 +55,7 @@ impl<'a> AstConverter<'a> { } } -pub enum VariableDeclaration<'a> { +pub(crate) enum VariableDeclaration<'a> { Var(&'a VarDecl), Using(&'a UsingDecl), } diff --git a/rust/parse_ast/src/ast_nodes/variable_declarator.rs b/rust/parse_ast/src/ast_nodes/variable_declarator.rs index d7d421197f2..552acfcaa44 100644 --- a/rust/parse_ast/src/ast_nodes/variable_declarator.rs +++ b/rust/parse_ast/src/ast_nodes/variable_declarator.rs @@ -2,13 +2,13 @@ use swc_ecma_ast::{Expr, VarDeclarator}; use crate::convert_ast::annotations::AnnotationKind; use crate::convert_ast::converter::ast_constants::{ - TYPE_VARIABLE_DECLARATOR, VARIABLE_DECLARATOR_ID_OFFSET, VARIABLE_DECLARATOR_INIT_OFFSET, - VARIABLE_DECLARATOR_RESERVED_BYTES, + TYPE_VARIABLE_DECLARATOR, VARIABLE_DECLARATOR_ID_OFFSET, VARIABLE_DECLARATOR_INIT_OFFSET, + VARIABLE_DECLARATOR_RESERVED_BYTES, }; use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_variable_declarator(&mut self, variable_declarator: &VarDeclarator) { + pub(crate) fn store_variable_declarator(&mut self, variable_declarator: &VarDeclarator) { let end_position = self.add_type_and_start( &TYPE_VARIABLE_DECLARATOR, &variable_declarator.span, diff --git a/rust/parse_ast/src/ast_nodes/while_statement.rs b/rust/parse_ast/src/ast_nodes/while_statement.rs index d135253558c..42e00184ba9 100644 --- a/rust/parse_ast/src/ast_nodes/while_statement.rs +++ b/rust/parse_ast/src/ast_nodes/while_statement.rs @@ -4,7 +4,7 @@ use crate::convert_ast::converter::AstConverter; use crate::store_while_statement; impl<'a> AstConverter<'a> { - pub fn store_while_statement(&mut self, while_statement: &WhileStmt) { + pub(crate) fn store_while_statement(&mut self, while_statement: &WhileStmt) { store_while_statement!( self, span => &while_statement.span, diff --git a/rust/parse_ast/src/ast_nodes/yield_expression.rs b/rust/parse_ast/src/ast_nodes/yield_expression.rs index dbd4d3f9a84..99910d3078c 100644 --- a/rust/parse_ast/src/ast_nodes/yield_expression.rs +++ b/rust/parse_ast/src/ast_nodes/yield_expression.rs @@ -1,10 +1,10 @@ use swc_ecma_ast::YieldExpr; -use crate::convert_ast::converter::AstConverter; use crate::{store_yield_expression, store_yield_expression_flags}; +use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { - pub fn store_yield_expression(&mut self, yield_expression: &YieldExpr) { + pub(crate) fn store_yield_expression(&mut self, yield_expression: &YieldExpr) { store_yield_expression!( self, span => yield_expression.span, diff --git a/rust/parse_ast/src/convert_ast.rs b/rust/parse_ast/src/convert_ast.rs index e7d6154cdbf..9b9b1086064 100644 --- a/rust/parse_ast/src/convert_ast.rs +++ b/rust/parse_ast/src/convert_ast.rs @@ -1,2 +1,2 @@ -pub mod annotations; -pub mod converter; +pub(crate) mod annotations; +pub(crate) mod converter; diff --git a/rust/parse_ast/src/convert_ast/annotations.rs b/rust/parse_ast/src/convert_ast/annotations.rs index a5c61b835af..a624dc7902b 100644 --- a/rust/parse_ast/src/convert_ast/annotations.rs +++ b/rust/parse_ast/src/convert_ast/annotations.rs @@ -1,15 +1,15 @@ use std::cell::RefCell; -use swc_common::comments::{Comment, Comments}; use swc_common::BytePos; +use swc_common::comments::{Comment, Comments}; #[derive(Default)] -pub struct SequentialComments { +pub(crate) struct SequentialComments { annotations: RefCell>, } impl SequentialComments { - pub fn add_comment(&self, comment: Comment) { + pub(crate) fn add_comment(&self, comment: Comment) { if comment.text.starts_with('#') && comment.text.contains("sourceMappingURL=") { self.annotations.borrow_mut().push(AnnotationWithType { comment, @@ -55,7 +55,7 @@ impl SequentialComments { }); } - pub fn take_annotations(self) -> Vec { + pub(crate) fn take_annotations(self) -> Vec { self.annotations.take() } } @@ -127,19 +127,19 @@ impl Comments for SequentialComments { } #[derive(Debug)] -pub struct AnnotationWithType { - pub comment: Comment, - pub kind: CommentKind, +pub(crate) struct AnnotationWithType { + pub(crate) comment: Comment, + pub(crate) kind: CommentKind, } #[derive(Clone, Debug)] -pub enum CommentKind { +pub(crate) enum CommentKind { Annotation(AnnotationKind), Comment, } #[derive(Clone, PartialEq, Debug)] -pub enum AnnotationKind { +pub(crate) enum AnnotationKind { Pure, NoSideEffects, SourceMappingUrl, diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index bd773bb0c38..29f9cdb4cbe 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -21,20 +21,20 @@ use crate::convert_ast::converter::utf16_positions::{ }; pub(crate) mod analyze_code; -pub mod string_constants; +pub(crate) mod string_constants; mod utf16_positions; -pub mod ast_constants; +pub(crate) mod ast_constants; mod ast_macros; -pub struct AstConverter<'a> { - pub buffer: Vec, - pub code: &'a [u8], - pub index_converter: Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a>, +pub(crate) struct AstConverter<'a> { + pub(crate) buffer: Vec, + pub(crate) code: &'a [u8], + pub(crate) index_converter: Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a>, } impl<'a> AstConverter<'a> { - pub fn new(code: &'a str, annotations: &'a [AnnotationWithType]) -> Self { + pub(crate) fn new(code: &'a str, annotations: &'a [AnnotationWithType]) -> Self { Self { // This is just a wild guess and should be revisited from time to time buffer: Vec::with_capacity(20 * code.len()), @@ -43,14 +43,14 @@ impl<'a> AstConverter<'a> { } } - pub fn convert_ast_to_buffer(mut self, node: &Program) -> Vec { + pub(crate) fn convert_ast_to_buffer(mut self, node: &Program) -> Vec { self.convert_program(node); self.buffer.shrink_to_fit(); self.buffer } // === helpers - pub fn add_type_and_start( + pub(crate) fn add_type_and_start( &mut self, node_type: &[u8; 4], span: &Span, @@ -90,7 +90,7 @@ impl<'a> AstConverter<'a> { end_position } - pub fn add_end(&mut self, end_position: usize, span: &Span) { + pub(crate) fn add_end(&mut self, end_position: usize, span: &Span) { self.buffer[end_position..end_position + 4].copy_from_slice( &self .index_converter @@ -104,7 +104,7 @@ impl<'a> AstConverter<'a> { .copy_from_slice(&self.index_converter.convert(end, false).to_ne_bytes()); } - pub fn convert_item_list( + pub(crate) fn convert_item_list( &mut self, item_list: &[T], reference_position: usize, @@ -136,7 +136,7 @@ impl<'a> AstConverter<'a> { } } - pub fn convert_item_list_with_state( + pub(crate) fn convert_item_list_with_state( &mut self, item_list: &[T], state: &mut S, @@ -175,14 +175,14 @@ impl<'a> AstConverter<'a> { convert_string(&mut self.buffer, string); } - pub fn update_reference_position(&mut self, reference_position: usize) { + pub(crate) fn update_reference_position(&mut self, reference_position: usize) { let insert_position = (self.buffer.len() as u32) >> 2; self.buffer[reference_position..reference_position + 4] .copy_from_slice(&insert_position.to_ne_bytes()); } // === shared enums - pub fn convert_call_expression( + pub(crate) fn convert_call_expression( &mut self, call_expression: &CallExpr, is_optional: bool, @@ -276,7 +276,7 @@ impl<'a> AstConverter<'a> { } } - pub fn convert_expression(&mut self, expression: &Expr) { + pub(crate) fn convert_expression(&mut self, expression: &Expr) { match expression { Expr::Array(array_literal) => { self.store_array_expression(array_literal); @@ -379,7 +379,7 @@ impl<'a> AstConverter<'a> { } } - pub fn convert_expression_or_spread(&mut self, expression_or_spread: &ExprOrSpread) { + pub(crate) fn convert_expression_or_spread(&mut self, expression_or_spread: &ExprOrSpread) { match expression_or_spread.spread { Some(spread_span) => self.store_spread_element(&spread_span, &expression_or_spread.expr), None => { @@ -602,7 +602,7 @@ impl<'a> AstConverter<'a> { self.convert_expression(&parenthesized_expression.expr); } - pub fn convert_pattern(&mut self, pattern: &Pat) { + pub(crate) fn convert_pattern(&mut self, pattern: &Pat) { match pattern { Pat::Array(array_pattern) => { self.store_array_pattern(array_pattern); @@ -624,7 +624,7 @@ impl<'a> AstConverter<'a> { } } - pub fn convert_pattern_or_expression(&mut self, pattern_or_expression: &AssignTarget) { + pub(crate) fn convert_pattern_or_expression(&mut self, pattern_or_expression: &AssignTarget) { match pattern_or_expression { AssignTarget::Pat(assignment_target_pattern) => { self.convert_assignment_target_pattern(assignment_target_pattern); @@ -704,7 +704,7 @@ impl<'a> AstConverter<'a> { } } - pub fn convert_statement(&mut self, statement: &Stmt) { + pub(crate) fn convert_statement(&mut self, statement: &Stmt) { match statement { Stmt::Break(break_statement) => self.store_break_statement(break_statement), Stmt::Block(block_statement) => self.store_block_statement(block_statement, false), @@ -743,7 +743,7 @@ impl<'a> AstConverter<'a> { } } -pub fn convert_annotation(buffer: &mut Vec, annotation: &ConvertedAnnotation) { +pub(crate) fn convert_annotation(buffer: &mut Vec, annotation: &ConvertedAnnotation) { // start buffer.extend_from_slice(&annotation.start.to_ne_bytes()); // end @@ -756,7 +756,7 @@ pub fn convert_annotation(buffer: &mut Vec, annotation: &ConvertedAnnotation }); } -pub fn convert_string(buffer: &mut Vec, string: &str) { +pub(crate) fn convert_string(buffer: &mut Vec, string: &str) { let length = string.len(); let additional_length = ((length + 3) & !3) - length; buffer.extend_from_slice(&(length as u32).to_ne_bytes()); @@ -764,7 +764,7 @@ pub fn convert_string(buffer: &mut Vec, string: &str) { buffer.resize(buffer.len() + additional_length, 0); } -pub fn update_reference_position(buffer: &mut [u8], reference_position: usize) { +pub(crate) fn update_reference_position(buffer: &mut [u8], reference_position: usize) { let insert_position = (buffer.len() as u32) >> 2; buffer[reference_position..reference_position + 4] .copy_from_slice(&insert_position.to_ne_bytes()); diff --git a/rust/parse_ast/src/convert_ast/converter/analyze_code.rs b/rust/parse_ast/src/convert_ast/converter/analyze_code.rs index d2fb985df23..2aa770a98d9 100644 --- a/rust/parse_ast/src/convert_ast/converter/analyze_code.rs +++ b/rust/parse_ast/src/convert_ast/converter/analyze_code.rs @@ -1,4 +1,8 @@ -pub fn find_first_occurrence_outside_comment(code: &[u8], search_byte: u8, start: u32) -> u32 { +pub(crate) fn find_first_occurrence_outside_comment( + code: &[u8], + search_byte: u8, + start: u32, +) -> u32 { let mut search_pos = start as usize; let mut comment_type = CommentType::None; loop { diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index 0f310097cc6..d8334614f0b 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -1,248 +1,248 @@ // This file is generated by scripts/generate-rust-constants.js. // Do not edit this file directly. -pub const TYPE_PANIC_ERROR: [u8; 4] = 0u32.to_ne_bytes(); -pub const TYPE_PARSE_ERROR: [u8; 4] = 1u32.to_ne_bytes(); -pub const TYPE_ARRAY_EXPRESSION: [u8; 4] = 2u32.to_ne_bytes(); -pub const TYPE_ARRAY_PATTERN: [u8; 4] = 3u32.to_ne_bytes(); -pub const TYPE_ARROW_FUNCTION_EXPRESSION: [u8; 4] = 4u32.to_ne_bytes(); -pub const TYPE_ASSIGNMENT_PATTERN: [u8; 4] = 6u32.to_ne_bytes(); -pub const TYPE_BINARY_EXPRESSION: [u8; 4] = 8u32.to_ne_bytes(); -pub const TYPE_BLOCK_STATEMENT: [u8; 4] = 9u32.to_ne_bytes(); -pub const TYPE_CALL_EXPRESSION: [u8; 4] = 11u32.to_ne_bytes(); -pub const TYPE_CATCH_CLAUSE: [u8; 4] = 12u32.to_ne_bytes(); -pub const TYPE_CHAIN_EXPRESSION: [u8; 4] = 13u32.to_ne_bytes(); -pub const TYPE_CLASS_BODY: [u8; 4] = 14u32.to_ne_bytes(); -pub const TYPE_CLASS_DECLARATION: [u8; 4] = 15u32.to_ne_bytes(); -pub const TYPE_CLASS_EXPRESSION: [u8; 4] = 16u32.to_ne_bytes(); -pub const TYPE_EXPORT_ALL_DECLARATION: [u8; 4] = 24u32.to_ne_bytes(); -pub const TYPE_EXPORT_DEFAULT_DECLARATION: [u8; 4] = 25u32.to_ne_bytes(); -pub const TYPE_EXPORT_NAMED_DECLARATION: [u8; 4] = 26u32.to_ne_bytes(); -pub const TYPE_FUNCTION_DECLARATION: [u8; 4] = 32u32.to_ne_bytes(); -pub const TYPE_FUNCTION_EXPRESSION: [u8; 4] = 33u32.to_ne_bytes(); -pub const TYPE_IDENTIFIER: [u8; 4] = 34u32.to_ne_bytes(); -pub const TYPE_IMPORT_ATTRIBUTE: [u8; 4] = 36u32.to_ne_bytes(); -pub const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); -pub const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); -pub const TYPE_JSX_ATTRIBUTE: [u8; 4] = 42u32.to_ne_bytes(); -pub const TYPE_JSX_CLOSING_ELEMENT: [u8; 4] = 43u32.to_ne_bytes(); -pub const TYPE_JSX_CLOSING_FRAGMENT: [u8; 4] = 44u32.to_ne_bytes(); -pub const TYPE_JSX_ELEMENT: [u8; 4] = 45u32.to_ne_bytes(); -pub const TYPE_JSX_EMPTY_EXPRESSION: [u8; 4] = 46u32.to_ne_bytes(); -pub const TYPE_JSX_EXPRESSION_CONTAINER: [u8; 4] = 47u32.to_ne_bytes(); -pub const TYPE_JSX_FRAGMENT: [u8; 4] = 48u32.to_ne_bytes(); -pub const TYPE_JSX_IDENTIFIER: [u8; 4] = 49u32.to_ne_bytes(); -pub const TYPE_JSX_MEMBER_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); -pub const TYPE_JSX_NAMESPACED_NAME: [u8; 4] = 51u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 52u32.to_ne_bytes(); -pub const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 53u32.to_ne_bytes(); -pub const TYPE_JSX_SPREAD_ATTRIBUTE: [u8; 4] = 54u32.to_ne_bytes(); -pub const TYPE_JSX_SPREAD_CHILD: [u8; 4] = 55u32.to_ne_bytes(); -pub const TYPE_JSX_TEXT: [u8; 4] = 56u32.to_ne_bytes(); -pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 64u32.to_ne_bytes(); -pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 65u32.to_ne_bytes(); -pub const TYPE_META_PROPERTY: [u8; 4] = 66u32.to_ne_bytes(); -pub const TYPE_METHOD_DEFINITION: [u8; 4] = 67u32.to_ne_bytes(); -pub const TYPE_NEW_EXPRESSION: [u8; 4] = 68u32.to_ne_bytes(); -pub const TYPE_PROGRAM: [u8; 4] = 72u32.to_ne_bytes(); -pub const TYPE_PROPERTY: [u8; 4] = 73u32.to_ne_bytes(); -pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 74u32.to_ne_bytes(); -pub const TYPE_REST_ELEMENT: [u8; 4] = 75u32.to_ne_bytes(); -pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 78u32.to_ne_bytes(); -pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 85u32.to_ne_bytes(); -pub const TYPE_TRY_STATEMENT: [u8; 4] = 88u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 91u32.to_ne_bytes(); -pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 92u32.to_ne_bytes(); - -pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; -pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; - -pub const PARSE_ERROR_RESERVED_BYTES: usize = 8; -pub const PARSE_ERROR_MESSAGE_OFFSET: usize = 4; - -pub const ARRAY_EXPRESSION_RESERVED_BYTES: usize = 8; -pub const ARRAY_EXPRESSION_ELEMENTS_OFFSET: usize = 4; - -pub const ARRAY_PATTERN_RESERVED_BYTES: usize = 8; -pub const ARRAY_PATTERN_ELEMENTS_OFFSET: usize = 4; - -pub const ARROW_FUNCTION_EXPRESSION_RESERVED_BYTES: usize = 20; -pub const ARROW_FUNCTION_EXPRESSION_ANNOTATIONS_OFFSET: usize = 8; -pub const ARROW_FUNCTION_EXPRESSION_PARAMS_OFFSET: usize = 12; -pub const ARROW_FUNCTION_EXPRESSION_BODY_OFFSET: usize = 16; - -pub const ASSIGNMENT_PATTERN_RESERVED_BYTES: usize = 12; -pub const ASSIGNMENT_PATTERN_LEFT_OFFSET: usize = 4; -pub const ASSIGNMENT_PATTERN_RIGHT_OFFSET: usize = 8; - -pub const BINARY_EXPRESSION_RESERVED_BYTES: usize = 16; -pub const BINARY_EXPRESSION_OPERATOR_OFFSET: usize = 4; -pub const BINARY_EXPRESSION_LEFT_OFFSET: usize = 8; -pub const BINARY_EXPRESSION_RIGHT_OFFSET: usize = 12; - -pub const BLOCK_STATEMENT_RESERVED_BYTES: usize = 8; -pub const BLOCK_STATEMENT_BODY_OFFSET: usize = 4; - -pub const CALL_EXPRESSION_RESERVED_BYTES: usize = 20; -pub const CALL_EXPRESSION_ANNOTATIONS_OFFSET: usize = 8; -pub const CALL_EXPRESSION_CALLEE_OFFSET: usize = 12; -pub const CALL_EXPRESSION_ARGUMENTS_OFFSET: usize = 16; - -pub const CATCH_CLAUSE_RESERVED_BYTES: usize = 12; -pub const CATCH_CLAUSE_PARAM_OFFSET: usize = 4; -pub const CATCH_CLAUSE_BODY_OFFSET: usize = 8; - -pub const CHAIN_EXPRESSION_RESERVED_BYTES: usize = 8; -pub const CHAIN_EXPRESSION_EXPRESSION_OFFSET: usize = 4; - -pub const CLASS_BODY_RESERVED_BYTES: usize = 8; -pub const CLASS_BODY_BODY_OFFSET: usize = 4; - -pub const CLASS_DECLARATION_RESERVED_BYTES: usize = 20; -pub const CLASS_DECLARATION_DECORATORS_OFFSET: usize = 4; -pub const CLASS_DECLARATION_ID_OFFSET: usize = 8; -pub const CLASS_DECLARATION_SUPER_CLASS_OFFSET: usize = 12; -pub const CLASS_DECLARATION_BODY_OFFSET: usize = 16; - -pub const EXPORT_ALL_DECLARATION_RESERVED_BYTES: usize = 16; -pub const EXPORT_ALL_DECLARATION_EXPORTED_OFFSET: usize = 4; -pub const EXPORT_ALL_DECLARATION_SOURCE_OFFSET: usize = 8; -pub const EXPORT_ALL_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; - -pub const EXPORT_DEFAULT_DECLARATION_RESERVED_BYTES: usize = 8; -pub const EXPORT_DEFAULT_DECLARATION_DECLARATION_OFFSET: usize = 4; - -pub const EXPORT_NAMED_DECLARATION_RESERVED_BYTES: usize = 20; -pub const EXPORT_NAMED_DECLARATION_SPECIFIERS_OFFSET: usize = 4; -pub const EXPORT_NAMED_DECLARATION_SOURCE_OFFSET: usize = 8; -pub const EXPORT_NAMED_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; -pub const EXPORT_NAMED_DECLARATION_DECLARATION_OFFSET: usize = 16; - -pub const FUNCTION_DECLARATION_RESERVED_BYTES: usize = 24; -pub const FUNCTION_DECLARATION_ANNOTATIONS_OFFSET: usize = 8; -pub const FUNCTION_DECLARATION_ID_OFFSET: usize = 12; -pub const FUNCTION_DECLARATION_PARAMS_OFFSET: usize = 16; -pub const FUNCTION_DECLARATION_BODY_OFFSET: usize = 20; - -pub const IDENTIFIER_RESERVED_BYTES: usize = 8; -pub const IDENTIFIER_NAME_OFFSET: usize = 4; - -pub const IMPORT_ATTRIBUTE_RESERVED_BYTES: usize = 12; -pub const IMPORT_ATTRIBUTE_KEY_OFFSET: usize = 4; -pub const IMPORT_ATTRIBUTE_VALUE_OFFSET: usize = 8; - -pub const IMPORT_DECLARATION_RESERVED_BYTES: usize = 16; -pub const IMPORT_DECLARATION_SPECIFIERS_OFFSET: usize = 4; -pub const IMPORT_DECLARATION_SOURCE_OFFSET: usize = 8; -pub const IMPORT_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; - -pub const IMPORT_EXPRESSION_RESERVED_BYTES: usize = 12; -pub const IMPORT_EXPRESSION_SOURCE_OFFSET: usize = 4; -pub const IMPORT_EXPRESSION_OPTIONS_OFFSET: usize = 8; - -pub const JSX_ATTRIBUTE_RESERVED_BYTES: usize = 12; -pub const JSX_ATTRIBUTE_NAME_OFFSET: usize = 4; -pub const JSX_ATTRIBUTE_VALUE_OFFSET: usize = 8; - -pub const JSX_CLOSING_ELEMENT_RESERVED_BYTES: usize = 8; -pub const JSX_CLOSING_ELEMENT_NAME_OFFSET: usize = 4; - -pub const JSX_CLOSING_FRAGMENT_RESERVED_BYTES: usize = 4; +pub(crate) const TYPE_PANIC_ERROR: [u8; 4] = 0u32.to_ne_bytes(); +pub(crate) const TYPE_PARSE_ERROR: [u8; 4] = 1u32.to_ne_bytes(); +pub(crate) const TYPE_ARRAY_EXPRESSION: [u8; 4] = 2u32.to_ne_bytes(); +pub(crate) const TYPE_ARRAY_PATTERN: [u8; 4] = 3u32.to_ne_bytes(); +pub(crate) const TYPE_ARROW_FUNCTION_EXPRESSION: [u8; 4] = 4u32.to_ne_bytes(); +pub(crate) const TYPE_ASSIGNMENT_PATTERN: [u8; 4] = 6u32.to_ne_bytes(); +pub(crate) const TYPE_BINARY_EXPRESSION: [u8; 4] = 8u32.to_ne_bytes(); +pub(crate) const TYPE_BLOCK_STATEMENT: [u8; 4] = 9u32.to_ne_bytes(); +pub(crate) const TYPE_CALL_EXPRESSION: [u8; 4] = 11u32.to_ne_bytes(); +pub(crate) const TYPE_CATCH_CLAUSE: [u8; 4] = 12u32.to_ne_bytes(); +pub(crate) const TYPE_CHAIN_EXPRESSION: [u8; 4] = 13u32.to_ne_bytes(); +pub(crate) const TYPE_CLASS_BODY: [u8; 4] = 14u32.to_ne_bytes(); +pub(crate) const TYPE_CLASS_DECLARATION: [u8; 4] = 15u32.to_ne_bytes(); +pub(crate) const TYPE_CLASS_EXPRESSION: [u8; 4] = 16u32.to_ne_bytes(); +pub(crate) const TYPE_EXPORT_ALL_DECLARATION: [u8; 4] = 24u32.to_ne_bytes(); +pub(crate) const TYPE_EXPORT_DEFAULT_DECLARATION: [u8; 4] = 25u32.to_ne_bytes(); +pub(crate) const TYPE_EXPORT_NAMED_DECLARATION: [u8; 4] = 26u32.to_ne_bytes(); +pub(crate) const TYPE_FUNCTION_DECLARATION: [u8; 4] = 32u32.to_ne_bytes(); +pub(crate) const TYPE_FUNCTION_EXPRESSION: [u8; 4] = 33u32.to_ne_bytes(); +pub(crate) const TYPE_IDENTIFIER: [u8; 4] = 34u32.to_ne_bytes(); +pub(crate) const TYPE_IMPORT_ATTRIBUTE: [u8; 4] = 36u32.to_ne_bytes(); +pub(crate) const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); +pub(crate) const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_ATTRIBUTE: [u8; 4] = 42u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_CLOSING_ELEMENT: [u8; 4] = 43u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_CLOSING_FRAGMENT: [u8; 4] = 44u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_ELEMENT: [u8; 4] = 45u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_EMPTY_EXPRESSION: [u8; 4] = 46u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_EXPRESSION_CONTAINER: [u8; 4] = 47u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_FRAGMENT: [u8; 4] = 48u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_IDENTIFIER: [u8; 4] = 49u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_MEMBER_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_NAMESPACED_NAME: [u8; 4] = 51u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 52u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 53u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_SPREAD_ATTRIBUTE: [u8; 4] = 54u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_SPREAD_CHILD: [u8; 4] = 55u32.to_ne_bytes(); +pub(crate) const TYPE_JSX_TEXT: [u8; 4] = 56u32.to_ne_bytes(); +pub(crate) const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 64u32.to_ne_bytes(); +pub(crate) const TYPE_MEMBER_EXPRESSION: [u8; 4] = 65u32.to_ne_bytes(); +pub(crate) const TYPE_META_PROPERTY: [u8; 4] = 66u32.to_ne_bytes(); +pub(crate) const TYPE_METHOD_DEFINITION: [u8; 4] = 67u32.to_ne_bytes(); +pub(crate) const TYPE_NEW_EXPRESSION: [u8; 4] = 68u32.to_ne_bytes(); +pub(crate) const TYPE_PROGRAM: [u8; 4] = 72u32.to_ne_bytes(); +pub(crate) const TYPE_PROPERTY: [u8; 4] = 73u32.to_ne_bytes(); +pub(crate) const TYPE_PROPERTY_DEFINITION: [u8; 4] = 74u32.to_ne_bytes(); +pub(crate) const TYPE_REST_ELEMENT: [u8; 4] = 75u32.to_ne_bytes(); +pub(crate) const TYPE_SPREAD_ELEMENT: [u8; 4] = 78u32.to_ne_bytes(); +pub(crate) const TYPE_TEMPLATE_LITERAL: [u8; 4] = 85u32.to_ne_bytes(); +pub(crate) const TYPE_TRY_STATEMENT: [u8; 4] = 88u32.to_ne_bytes(); +pub(crate) const TYPE_VARIABLE_DECLARATION: [u8; 4] = 91u32.to_ne_bytes(); +pub(crate) const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 92u32.to_ne_bytes(); + +pub(crate) const PANIC_ERROR_RESERVED_BYTES: usize = 8; +pub(crate) const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; + +pub(crate) const PARSE_ERROR_RESERVED_BYTES: usize = 8; +pub(crate) const PARSE_ERROR_MESSAGE_OFFSET: usize = 4; + +pub(crate) const ARRAY_EXPRESSION_RESERVED_BYTES: usize = 8; +pub(crate) const ARRAY_EXPRESSION_ELEMENTS_OFFSET: usize = 4; + +pub(crate) const ARRAY_PATTERN_RESERVED_BYTES: usize = 8; +pub(crate) const ARRAY_PATTERN_ELEMENTS_OFFSET: usize = 4; + +pub(crate) const ARROW_FUNCTION_EXPRESSION_RESERVED_BYTES: usize = 20; +pub(crate) const ARROW_FUNCTION_EXPRESSION_ANNOTATIONS_OFFSET: usize = 8; +pub(crate) const ARROW_FUNCTION_EXPRESSION_PARAMS_OFFSET: usize = 12; +pub(crate) const ARROW_FUNCTION_EXPRESSION_BODY_OFFSET: usize = 16; + +pub(crate) const ASSIGNMENT_PATTERN_RESERVED_BYTES: usize = 12; +pub(crate) const ASSIGNMENT_PATTERN_LEFT_OFFSET: usize = 4; +pub(crate) const ASSIGNMENT_PATTERN_RIGHT_OFFSET: usize = 8; + +pub(crate) const BINARY_EXPRESSION_RESERVED_BYTES: usize = 16; +pub(crate) const BINARY_EXPRESSION_OPERATOR_OFFSET: usize = 4; +pub(crate) const BINARY_EXPRESSION_LEFT_OFFSET: usize = 8; +pub(crate) const BINARY_EXPRESSION_RIGHT_OFFSET: usize = 12; + +pub(crate) const BLOCK_STATEMENT_RESERVED_BYTES: usize = 8; +pub(crate) const BLOCK_STATEMENT_BODY_OFFSET: usize = 4; + +pub(crate) const CALL_EXPRESSION_RESERVED_BYTES: usize = 20; +pub(crate) const CALL_EXPRESSION_ANNOTATIONS_OFFSET: usize = 8; +pub(crate) const CALL_EXPRESSION_CALLEE_OFFSET: usize = 12; +pub(crate) const CALL_EXPRESSION_ARGUMENTS_OFFSET: usize = 16; + +pub(crate) const CATCH_CLAUSE_RESERVED_BYTES: usize = 12; +pub(crate) const CATCH_CLAUSE_PARAM_OFFSET: usize = 4; +pub(crate) const CATCH_CLAUSE_BODY_OFFSET: usize = 8; + +pub(crate) const CHAIN_EXPRESSION_RESERVED_BYTES: usize = 8; +pub(crate) const CHAIN_EXPRESSION_EXPRESSION_OFFSET: usize = 4; + +pub(crate) const CLASS_BODY_RESERVED_BYTES: usize = 8; +pub(crate) const CLASS_BODY_BODY_OFFSET: usize = 4; + +pub(crate) const CLASS_DECLARATION_RESERVED_BYTES: usize = 20; +pub(crate) const CLASS_DECLARATION_DECORATORS_OFFSET: usize = 4; +pub(crate) const CLASS_DECLARATION_ID_OFFSET: usize = 8; +pub(crate) const CLASS_DECLARATION_SUPER_CLASS_OFFSET: usize = 12; +pub(crate) const CLASS_DECLARATION_BODY_OFFSET: usize = 16; + +pub(crate) const EXPORT_ALL_DECLARATION_RESERVED_BYTES: usize = 16; +pub(crate) const EXPORT_ALL_DECLARATION_EXPORTED_OFFSET: usize = 4; +pub(crate) const EXPORT_ALL_DECLARATION_SOURCE_OFFSET: usize = 8; +pub(crate) const EXPORT_ALL_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; + +pub(crate) const EXPORT_DEFAULT_DECLARATION_RESERVED_BYTES: usize = 8; +pub(crate) const EXPORT_DEFAULT_DECLARATION_DECLARATION_OFFSET: usize = 4; + +pub(crate) const EXPORT_NAMED_DECLARATION_RESERVED_BYTES: usize = 20; +pub(crate) const EXPORT_NAMED_DECLARATION_SPECIFIERS_OFFSET: usize = 4; +pub(crate) const EXPORT_NAMED_DECLARATION_SOURCE_OFFSET: usize = 8; +pub(crate) const EXPORT_NAMED_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; +pub(crate) const EXPORT_NAMED_DECLARATION_DECLARATION_OFFSET: usize = 16; + +pub(crate) const FUNCTION_DECLARATION_RESERVED_BYTES: usize = 24; +pub(crate) const FUNCTION_DECLARATION_ANNOTATIONS_OFFSET: usize = 8; +pub(crate) const FUNCTION_DECLARATION_ID_OFFSET: usize = 12; +pub(crate) const FUNCTION_DECLARATION_PARAMS_OFFSET: usize = 16; +pub(crate) const FUNCTION_DECLARATION_BODY_OFFSET: usize = 20; + +pub(crate) const IDENTIFIER_RESERVED_BYTES: usize = 8; +pub(crate) const IDENTIFIER_NAME_OFFSET: usize = 4; + +pub(crate) const IMPORT_ATTRIBUTE_RESERVED_BYTES: usize = 12; +pub(crate) const IMPORT_ATTRIBUTE_KEY_OFFSET: usize = 4; +pub(crate) const IMPORT_ATTRIBUTE_VALUE_OFFSET: usize = 8; + +pub(crate) const IMPORT_DECLARATION_RESERVED_BYTES: usize = 16; +pub(crate) const IMPORT_DECLARATION_SPECIFIERS_OFFSET: usize = 4; +pub(crate) const IMPORT_DECLARATION_SOURCE_OFFSET: usize = 8; +pub(crate) const IMPORT_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; + +pub(crate) const IMPORT_EXPRESSION_RESERVED_BYTES: usize = 12; +pub(crate) const IMPORT_EXPRESSION_SOURCE_OFFSET: usize = 4; +pub(crate) const IMPORT_EXPRESSION_OPTIONS_OFFSET: usize = 8; + +pub(crate) const JSX_ATTRIBUTE_RESERVED_BYTES: usize = 12; +pub(crate) const JSX_ATTRIBUTE_NAME_OFFSET: usize = 4; +pub(crate) const JSX_ATTRIBUTE_VALUE_OFFSET: usize = 8; + +pub(crate) const JSX_CLOSING_ELEMENT_RESERVED_BYTES: usize = 8; +pub(crate) const JSX_CLOSING_ELEMENT_NAME_OFFSET: usize = 4; + +pub(crate) const JSX_CLOSING_FRAGMENT_RESERVED_BYTES: usize = 4; -pub const JSX_ELEMENT_RESERVED_BYTES: usize = 16; -pub const JSX_ELEMENT_OPENING_ELEMENT_OFFSET: usize = 4; -pub const JSX_ELEMENT_CHILDREN_OFFSET: usize = 8; -pub const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 12; +pub(crate) const JSX_ELEMENT_RESERVED_BYTES: usize = 16; +pub(crate) const JSX_ELEMENT_OPENING_ELEMENT_OFFSET: usize = 4; +pub(crate) const JSX_ELEMENT_CHILDREN_OFFSET: usize = 8; +pub(crate) const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 12; -pub const JSX_EMPTY_EXPRESSION_RESERVED_BYTES: usize = 4; +pub(crate) const JSX_EMPTY_EXPRESSION_RESERVED_BYTES: usize = 4; -pub const JSX_EXPRESSION_CONTAINER_RESERVED_BYTES: usize = 8; -pub const JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET: usize = 4; +pub(crate) const JSX_EXPRESSION_CONTAINER_RESERVED_BYTES: usize = 8; +pub(crate) const JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET: usize = 4; -pub const JSX_FRAGMENT_RESERVED_BYTES: usize = 16; -pub const JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET: usize = 4; -pub const JSX_FRAGMENT_CHILDREN_OFFSET: usize = 8; -pub const JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET: usize = 12; +pub(crate) const JSX_FRAGMENT_RESERVED_BYTES: usize = 16; +pub(crate) const JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET: usize = 4; +pub(crate) const JSX_FRAGMENT_CHILDREN_OFFSET: usize = 8; +pub(crate) const JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET: usize = 12; -pub const JSX_IDENTIFIER_RESERVED_BYTES: usize = 8; -pub const JSX_IDENTIFIER_NAME_OFFSET: usize = 4; - -pub const JSX_MEMBER_EXPRESSION_RESERVED_BYTES: usize = 12; -pub const JSX_MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 4; -pub const JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 8; +pub(crate) const JSX_IDENTIFIER_RESERVED_BYTES: usize = 8; +pub(crate) const JSX_IDENTIFIER_NAME_OFFSET: usize = 4; + +pub(crate) const JSX_MEMBER_EXPRESSION_RESERVED_BYTES: usize = 12; +pub(crate) const JSX_MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 4; +pub(crate) const JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 8; -pub const JSX_NAMESPACED_NAME_RESERVED_BYTES: usize = 12; -pub const JSX_NAMESPACED_NAME_NAMESPACE_OFFSET: usize = 4; -pub const JSX_NAMESPACED_NAME_NAME_OFFSET: usize = 8; +pub(crate) const JSX_NAMESPACED_NAME_RESERVED_BYTES: usize = 12; +pub(crate) const JSX_NAMESPACED_NAME_NAMESPACE_OFFSET: usize = 4; +pub(crate) const JSX_NAMESPACED_NAME_NAME_OFFSET: usize = 8; -pub const JSX_OPENING_ELEMENT_RESERVED_BYTES: usize = 16; -pub const JSX_OPENING_ELEMENT_NAME_OFFSET: usize = 8; -pub const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; +pub(crate) const JSX_OPENING_ELEMENT_RESERVED_BYTES: usize = 16; +pub(crate) const JSX_OPENING_ELEMENT_NAME_OFFSET: usize = 8; +pub(crate) const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; -pub const JSX_OPENING_FRAGMENT_RESERVED_BYTES: usize = 4; +pub(crate) const JSX_OPENING_FRAGMENT_RESERVED_BYTES: usize = 4; -pub const JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES: usize = 8; -pub const JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET: usize = 4; +pub(crate) const JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES: usize = 8; +pub(crate) const JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET: usize = 4; -pub const JSX_SPREAD_CHILD_RESERVED_BYTES: usize = 8; -pub const JSX_SPREAD_CHILD_EXPRESSION_OFFSET: usize = 4; +pub(crate) const JSX_SPREAD_CHILD_RESERVED_BYTES: usize = 8; +pub(crate) const JSX_SPREAD_CHILD_EXPRESSION_OFFSET: usize = 4; -pub const JSX_TEXT_RESERVED_BYTES: usize = 12; -pub const JSX_TEXT_VALUE_OFFSET: usize = 4; -pub const JSX_TEXT_RAW_OFFSET: usize = 8; +pub(crate) const JSX_TEXT_RESERVED_BYTES: usize = 12; +pub(crate) const JSX_TEXT_VALUE_OFFSET: usize = 4; +pub(crate) const JSX_TEXT_RAW_OFFSET: usize = 8; -pub const MEMBER_EXPRESSION_RESERVED_BYTES: usize = 16; -pub const MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 8; -pub const MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 12; +pub(crate) const MEMBER_EXPRESSION_RESERVED_BYTES: usize = 16; +pub(crate) const MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 8; +pub(crate) const MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 12; -pub const META_PROPERTY_RESERVED_BYTES: usize = 12; -pub const META_PROPERTY_META_OFFSET: usize = 4; -pub const META_PROPERTY_PROPERTY_OFFSET: usize = 8; - -pub const METHOD_DEFINITION_RESERVED_BYTES: usize = 24; -pub const METHOD_DEFINITION_DECORATORS_OFFSET: usize = 8; -pub const METHOD_DEFINITION_KEY_OFFSET: usize = 12; -pub const METHOD_DEFINITION_VALUE_OFFSET: usize = 16; -pub const METHOD_DEFINITION_KIND_OFFSET: usize = 20; +pub(crate) const META_PROPERTY_RESERVED_BYTES: usize = 12; +pub(crate) const META_PROPERTY_META_OFFSET: usize = 4; +pub(crate) const META_PROPERTY_PROPERTY_OFFSET: usize = 8; + +pub(crate) const METHOD_DEFINITION_RESERVED_BYTES: usize = 24; +pub(crate) const METHOD_DEFINITION_DECORATORS_OFFSET: usize = 8; +pub(crate) const METHOD_DEFINITION_KEY_OFFSET: usize = 12; +pub(crate) const METHOD_DEFINITION_VALUE_OFFSET: usize = 16; +pub(crate) const METHOD_DEFINITION_KIND_OFFSET: usize = 20; -pub const NEW_EXPRESSION_RESERVED_BYTES: usize = 16; -pub const NEW_EXPRESSION_ANNOTATIONS_OFFSET: usize = 4; -pub const NEW_EXPRESSION_CALLEE_OFFSET: usize = 8; -pub const NEW_EXPRESSION_ARGUMENTS_OFFSET: usize = 12; +pub(crate) const NEW_EXPRESSION_RESERVED_BYTES: usize = 16; +pub(crate) const NEW_EXPRESSION_ANNOTATIONS_OFFSET: usize = 4; +pub(crate) const NEW_EXPRESSION_CALLEE_OFFSET: usize = 8; +pub(crate) const NEW_EXPRESSION_ARGUMENTS_OFFSET: usize = 12; -pub const PROGRAM_RESERVED_BYTES: usize = 12; -pub const PROGRAM_BODY_OFFSET: usize = 4; -pub const PROGRAM_INVALID_ANNOTATIONS_OFFSET: usize = 8; +pub(crate) const PROGRAM_RESERVED_BYTES: usize = 12; +pub(crate) const PROGRAM_BODY_OFFSET: usize = 4; +pub(crate) const PROGRAM_INVALID_ANNOTATIONS_OFFSET: usize = 8; -pub const PROPERTY_RESERVED_BYTES: usize = 20; -pub const PROPERTY_KEY_OFFSET: usize = 8; -pub const PROPERTY_VALUE_OFFSET: usize = 12; -pub const PROPERTY_KIND_OFFSET: usize = 16; +pub(crate) const PROPERTY_RESERVED_BYTES: usize = 20; +pub(crate) const PROPERTY_KEY_OFFSET: usize = 8; +pub(crate) const PROPERTY_VALUE_OFFSET: usize = 12; +pub(crate) const PROPERTY_KIND_OFFSET: usize = 16; -pub const PROPERTY_DEFINITION_RESERVED_BYTES: usize = 20; -pub const PROPERTY_DEFINITION_DECORATORS_OFFSET: usize = 8; -pub const PROPERTY_DEFINITION_KEY_OFFSET: usize = 12; -pub const PROPERTY_DEFINITION_VALUE_OFFSET: usize = 16; +pub(crate) const PROPERTY_DEFINITION_RESERVED_BYTES: usize = 20; +pub(crate) const PROPERTY_DEFINITION_DECORATORS_OFFSET: usize = 8; +pub(crate) const PROPERTY_DEFINITION_KEY_OFFSET: usize = 12; +pub(crate) const PROPERTY_DEFINITION_VALUE_OFFSET: usize = 16; -pub const REST_ELEMENT_RESERVED_BYTES: usize = 8; -pub const REST_ELEMENT_ARGUMENT_OFFSET: usize = 4; +pub(crate) const REST_ELEMENT_RESERVED_BYTES: usize = 8; +pub(crate) const REST_ELEMENT_ARGUMENT_OFFSET: usize = 4; -pub const SPREAD_ELEMENT_RESERVED_BYTES: usize = 8; -pub const SPREAD_ELEMENT_ARGUMENT_OFFSET: usize = 4; +pub(crate) const SPREAD_ELEMENT_RESERVED_BYTES: usize = 8; +pub(crate) const SPREAD_ELEMENT_ARGUMENT_OFFSET: usize = 4; -pub const TEMPLATE_LITERAL_RESERVED_BYTES: usize = 12; -pub const TEMPLATE_LITERAL_QUASIS_OFFSET: usize = 4; -pub const TEMPLATE_LITERAL_EXPRESSIONS_OFFSET: usize = 8; +pub(crate) const TEMPLATE_LITERAL_RESERVED_BYTES: usize = 12; +pub(crate) const TEMPLATE_LITERAL_QUASIS_OFFSET: usize = 4; +pub(crate) const TEMPLATE_LITERAL_EXPRESSIONS_OFFSET: usize = 8; -pub const TRY_STATEMENT_RESERVED_BYTES: usize = 16; -pub const TRY_STATEMENT_BLOCK_OFFSET: usize = 4; -pub const TRY_STATEMENT_HANDLER_OFFSET: usize = 8; -pub const TRY_STATEMENT_FINALIZER_OFFSET: usize = 12; +pub(crate) const TRY_STATEMENT_RESERVED_BYTES: usize = 16; +pub(crate) const TRY_STATEMENT_BLOCK_OFFSET: usize = 4; +pub(crate) const TRY_STATEMENT_HANDLER_OFFSET: usize = 8; +pub(crate) const TRY_STATEMENT_FINALIZER_OFFSET: usize = 12; -pub const VARIABLE_DECLARATION_RESERVED_BYTES: usize = 12; -pub const VARIABLE_DECLARATION_KIND_OFFSET: usize = 4; -pub const VARIABLE_DECLARATION_DECLARATIONS_OFFSET: usize = 8; +pub(crate) const VARIABLE_DECLARATION_RESERVED_BYTES: usize = 12; +pub(crate) const VARIABLE_DECLARATION_KIND_OFFSET: usize = 4; +pub(crate) const VARIABLE_DECLARATION_DECLARATIONS_OFFSET: usize = 8; -pub const VARIABLE_DECLARATOR_RESERVED_BYTES: usize = 12; -pub const VARIABLE_DECLARATOR_ID_OFFSET: usize = 4; -pub const VARIABLE_DECLARATOR_INIT_OFFSET: usize = 8; +pub(crate) const VARIABLE_DECLARATOR_RESERVED_BYTES: usize = 12; +pub(crate) const VARIABLE_DECLARATOR_ID_OFFSET: usize = 4; +pub(crate) const VARIABLE_DECLARATOR_INIT_OFFSET: usize = 8; diff --git a/rust/parse_ast/src/convert_ast/converter/string_constants.rs b/rust/parse_ast/src/convert_ast/converter/string_constants.rs index b5955be0eab..44bd9eed7a8 100644 --- a/rust/parse_ast/src/convert_ast/converter/string_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/string_constants.rs @@ -1,66 +1,66 @@ // This file is generated by scripts/generate-string-constants.js. // Do not edit this file directly. -pub const STRING_VAR: [u8; 4] = 0u32.to_ne_bytes(); // var -pub const STRING_LET: [u8; 4] = 1u32.to_ne_bytes(); // let -pub const STRING_CONST: [u8; 4] = 2u32.to_ne_bytes(); // const -pub const STRING_INIT: [u8; 4] = 3u32.to_ne_bytes(); // init -pub const STRING_GET: [u8; 4] = 4u32.to_ne_bytes(); // get -pub const STRING_SET: [u8; 4] = 5u32.to_ne_bytes(); // set -pub const STRING_CONSTRUCTOR: [u8; 4] = 6u32.to_ne_bytes(); // constructor -pub const STRING_METHOD: [u8; 4] = 7u32.to_ne_bytes(); // method -pub const STRING_MINUS: [u8; 4] = 8u32.to_ne_bytes(); // - -pub const STRING_PLUS: [u8; 4] = 9u32.to_ne_bytes(); // + -pub const STRING_BANG: [u8; 4] = 10u32.to_ne_bytes(); // ! -pub const STRING_TILDE: [u8; 4] = 11u32.to_ne_bytes(); // ~ -pub const STRING_TYPEOF: [u8; 4] = 12u32.to_ne_bytes(); // typeof -pub const STRING_VOID: [u8; 4] = 13u32.to_ne_bytes(); // void -pub const STRING_DELETE: [u8; 4] = 14u32.to_ne_bytes(); // delete -pub const STRING_PLUSPLUS: [u8; 4] = 15u32.to_ne_bytes(); // ++ -pub const STRING_MINUSMINUS: [u8; 4] = 16u32.to_ne_bytes(); // -- -pub const STRING_EQEQ: [u8; 4] = 17u32.to_ne_bytes(); // == -pub const STRING_NOTEQ: [u8; 4] = 18u32.to_ne_bytes(); // != -pub const STRING_EQEQEQ: [u8; 4] = 19u32.to_ne_bytes(); // === -pub const STRING_NOTEQEQ: [u8; 4] = 20u32.to_ne_bytes(); // !== -pub const STRING_LT: [u8; 4] = 21u32.to_ne_bytes(); // < -pub const STRING_LTEQ: [u8; 4] = 22u32.to_ne_bytes(); // <= -pub const STRING_GT: [u8; 4] = 23u32.to_ne_bytes(); // > -pub const STRING_GTEQ: [u8; 4] = 24u32.to_ne_bytes(); // >= -pub const STRING_LSHIFT: [u8; 4] = 25u32.to_ne_bytes(); // << -pub const STRING_RSHIFT: [u8; 4] = 26u32.to_ne_bytes(); // >> -pub const STRING_ZEROFILLRSHIFT: [u8; 4] = 27u32.to_ne_bytes(); // >>> -pub const STRING_ADD: [u8; 4] = 28u32.to_ne_bytes(); // + -pub const STRING_SUB: [u8; 4] = 29u32.to_ne_bytes(); // - -pub const STRING_MUL: [u8; 4] = 30u32.to_ne_bytes(); // * -pub const STRING_DIV: [u8; 4] = 31u32.to_ne_bytes(); // / -pub const STRING_MOD: [u8; 4] = 32u32.to_ne_bytes(); // % -pub const STRING_BITOR: [u8; 4] = 33u32.to_ne_bytes(); // | -pub const STRING_BITXOR: [u8; 4] = 34u32.to_ne_bytes(); // ^ -pub const STRING_BITAND: [u8; 4] = 35u32.to_ne_bytes(); // & -pub const STRING_LOGICALOR: [u8; 4] = 36u32.to_ne_bytes(); // || -pub const STRING_LOGICALAND: [u8; 4] = 37u32.to_ne_bytes(); // && -pub const STRING_IN: [u8; 4] = 38u32.to_ne_bytes(); // in -pub const STRING_INSTANCEOF: [u8; 4] = 39u32.to_ne_bytes(); // instanceof -pub const STRING_EXP: [u8; 4] = 40u32.to_ne_bytes(); // ** -pub const STRING_NULLISHCOALESCING: [u8; 4] = 41u32.to_ne_bytes(); // ?? -pub const STRING_ASSIGN: [u8; 4] = 42u32.to_ne_bytes(); // = -pub const STRING_ADDASSIGN: [u8; 4] = 43u32.to_ne_bytes(); // += -pub const STRING_SUBASSIGN: [u8; 4] = 44u32.to_ne_bytes(); // -= -pub const STRING_MULASSIGN: [u8; 4] = 45u32.to_ne_bytes(); // *= -pub const STRING_DIVASSIGN: [u8; 4] = 46u32.to_ne_bytes(); // /= -pub const STRING_MODASSIGN: [u8; 4] = 47u32.to_ne_bytes(); // %= -pub const STRING_LSHIFTASSIGN: [u8; 4] = 48u32.to_ne_bytes(); // <<= -pub const STRING_RSHIFTASSIGN: [u8; 4] = 49u32.to_ne_bytes(); // >>= -pub const STRING_ZEROFILLRSHIFTASSIGN: [u8; 4] = 50u32.to_ne_bytes(); // >>>= -pub const STRING_BITORASSIGN: [u8; 4] = 51u32.to_ne_bytes(); // |= -pub const STRING_BITXORASSIGN: [u8; 4] = 52u32.to_ne_bytes(); // ^= -pub const STRING_BITANDASSIGN: [u8; 4] = 53u32.to_ne_bytes(); // &= -pub const STRING_EXPASSIGN: [u8; 4] = 54u32.to_ne_bytes(); // **= -pub const STRING_ANDASSIGN: [u8; 4] = 55u32.to_ne_bytes(); // &&= -pub const STRING_ORASSIGN: [u8; 4] = 56u32.to_ne_bytes(); // ||= -pub const STRING_NULLISHASSIGN: [u8; 4] = 57u32.to_ne_bytes(); // ??= -pub const STRING_PURE: [u8; 4] = 58u32.to_ne_bytes(); // pure -pub const STRING_NOSIDEEFFECTS: [u8; 4] = 59u32.to_ne_bytes(); // noSideEffects -pub const STRING_SOURCEMAP: [u8; 4] = 60u32.to_ne_bytes(); // sourcemap -pub const STRING_USING: [u8; 4] = 61u32.to_ne_bytes(); // using -pub const STRING_AWAIT_USING: [u8; 4] = 62u32.to_ne_bytes(); // await using +pub(crate) const STRING_VAR: [u8; 4] = 0u32.to_ne_bytes(); // var +pub(crate) const STRING_LET: [u8; 4] = 1u32.to_ne_bytes(); // let +pub(crate) const STRING_CONST: [u8; 4] = 2u32.to_ne_bytes(); // const +pub(crate) const STRING_INIT: [u8; 4] = 3u32.to_ne_bytes(); // init +pub(crate) const STRING_GET: [u8; 4] = 4u32.to_ne_bytes(); // get +pub(crate) const STRING_SET: [u8; 4] = 5u32.to_ne_bytes(); // set +pub(crate) const STRING_CONSTRUCTOR: [u8; 4] = 6u32.to_ne_bytes(); // constructor +pub(crate) const STRING_METHOD: [u8; 4] = 7u32.to_ne_bytes(); // method +pub(crate) const STRING_MINUS: [u8; 4] = 8u32.to_ne_bytes(); // - +pub(crate) const STRING_PLUS: [u8; 4] = 9u32.to_ne_bytes(); // + +pub(crate) const STRING_BANG: [u8; 4] = 10u32.to_ne_bytes(); // ! +pub(crate) const STRING_TILDE: [u8; 4] = 11u32.to_ne_bytes(); // ~ +pub(crate) const STRING_TYPEOF: [u8; 4] = 12u32.to_ne_bytes(); // typeof +pub(crate) const STRING_VOID: [u8; 4] = 13u32.to_ne_bytes(); // void +pub(crate) const STRING_DELETE: [u8; 4] = 14u32.to_ne_bytes(); // delete +pub(crate) const STRING_PLUSPLUS: [u8; 4] = 15u32.to_ne_bytes(); // ++ +pub(crate) const STRING_MINUSMINUS: [u8; 4] = 16u32.to_ne_bytes(); // -- +pub(crate) const STRING_EQEQ: [u8; 4] = 17u32.to_ne_bytes(); // == +pub(crate) const STRING_NOTEQ: [u8; 4] = 18u32.to_ne_bytes(); // != +pub(crate) const STRING_EQEQEQ: [u8; 4] = 19u32.to_ne_bytes(); // === +pub(crate) const STRING_NOTEQEQ: [u8; 4] = 20u32.to_ne_bytes(); // !== +pub(crate) const STRING_LT: [u8; 4] = 21u32.to_ne_bytes(); // < +pub(crate) const STRING_LTEQ: [u8; 4] = 22u32.to_ne_bytes(); // <= +pub(crate) const STRING_GT: [u8; 4] = 23u32.to_ne_bytes(); // > +pub(crate) const STRING_GTEQ: [u8; 4] = 24u32.to_ne_bytes(); // >= +pub(crate) const STRING_LSHIFT: [u8; 4] = 25u32.to_ne_bytes(); // << +pub(crate) const STRING_RSHIFT: [u8; 4] = 26u32.to_ne_bytes(); // >> +pub(crate) const STRING_ZEROFILLRSHIFT: [u8; 4] = 27u32.to_ne_bytes(); // >>> +pub(crate) const STRING_ADD: [u8; 4] = 28u32.to_ne_bytes(); // + +pub(crate) const STRING_SUB: [u8; 4] = 29u32.to_ne_bytes(); // - +pub(crate) const STRING_MUL: [u8; 4] = 30u32.to_ne_bytes(); // * +pub(crate) const STRING_DIV: [u8; 4] = 31u32.to_ne_bytes(); // / +pub(crate) const STRING_MOD: [u8; 4] = 32u32.to_ne_bytes(); // % +pub(crate) const STRING_BITOR: [u8; 4] = 33u32.to_ne_bytes(); // | +pub(crate) const STRING_BITXOR: [u8; 4] = 34u32.to_ne_bytes(); // ^ +pub(crate) const STRING_BITAND: [u8; 4] = 35u32.to_ne_bytes(); // & +pub(crate) const STRING_LOGICALOR: [u8; 4] = 36u32.to_ne_bytes(); // || +pub(crate) const STRING_LOGICALAND: [u8; 4] = 37u32.to_ne_bytes(); // && +pub(crate) const STRING_IN: [u8; 4] = 38u32.to_ne_bytes(); // in +pub(crate) const STRING_INSTANCEOF: [u8; 4] = 39u32.to_ne_bytes(); // instanceof +pub(crate) const STRING_EXP: [u8; 4] = 40u32.to_ne_bytes(); // ** +pub(crate) const STRING_NULLISHCOALESCING: [u8; 4] = 41u32.to_ne_bytes(); // ?? +pub(crate) const STRING_ASSIGN: [u8; 4] = 42u32.to_ne_bytes(); // = +pub(crate) const STRING_ADDASSIGN: [u8; 4] = 43u32.to_ne_bytes(); // += +pub(crate) const STRING_SUBASSIGN: [u8; 4] = 44u32.to_ne_bytes(); // -= +pub(crate) const STRING_MULASSIGN: [u8; 4] = 45u32.to_ne_bytes(); // *= +pub(crate) const STRING_DIVASSIGN: [u8; 4] = 46u32.to_ne_bytes(); // /= +pub(crate) const STRING_MODASSIGN: [u8; 4] = 47u32.to_ne_bytes(); // %= +pub(crate) const STRING_LSHIFTASSIGN: [u8; 4] = 48u32.to_ne_bytes(); // <<= +pub(crate) const STRING_RSHIFTASSIGN: [u8; 4] = 49u32.to_ne_bytes(); // >>= +pub(crate) const STRING_ZEROFILLRSHIFTASSIGN: [u8; 4] = 50u32.to_ne_bytes(); // >>>= +pub(crate) const STRING_BITORASSIGN: [u8; 4] = 51u32.to_ne_bytes(); // |= +pub(crate) const STRING_BITXORASSIGN: [u8; 4] = 52u32.to_ne_bytes(); // ^= +pub(crate) const STRING_BITANDASSIGN: [u8; 4] = 53u32.to_ne_bytes(); // &= +pub(crate) const STRING_EXPASSIGN: [u8; 4] = 54u32.to_ne_bytes(); // **= +pub(crate) const STRING_ANDASSIGN: [u8; 4] = 55u32.to_ne_bytes(); // &&= +pub(crate) const STRING_ORASSIGN: [u8; 4] = 56u32.to_ne_bytes(); // ||= +pub(crate) const STRING_NULLISHASSIGN: [u8; 4] = 57u32.to_ne_bytes(); // ??= +pub(crate) const STRING_PURE: [u8; 4] = 58u32.to_ne_bytes(); // pure +pub(crate) const STRING_NOSIDEEFFECTS: [u8; 4] = 59u32.to_ne_bytes(); // noSideEffects +pub(crate) const STRING_SOURCEMAP: [u8; 4] = 60u32.to_ne_bytes(); // sourcemap +pub(crate) const STRING_USING: [u8; 4] = 61u32.to_ne_bytes(); // using +pub(crate) const STRING_AWAIT_USING: [u8; 4] = 62u32.to_ne_bytes(); // await using diff --git a/rust/parse_ast/src/convert_ast/converter/utf16_positions.rs b/rust/parse_ast/src/convert_ast/converter/utf16_positions.rs index 0d963b523c0..22b7ba34587 100644 --- a/rust/parse_ast/src/convert_ast/converter/utf16_positions.rs +++ b/rust/parse_ast/src/convert_ast/converter/utf16_positions.rs @@ -1,10 +1,10 @@ use std::slice::Iter; use std::str::Chars; -use crate::convert_ast::annotations::CommentKind::Annotation; use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; +use crate::convert_ast::annotations::CommentKind::Annotation; -pub struct Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a> { +pub(crate) struct Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a> { current_utf8_index: u32, current_utf16_index: u32, character_iterator: Chars<'a>, @@ -17,14 +17,14 @@ pub struct Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a> { } #[derive(Debug)] -pub struct ConvertedAnnotation { - pub start: u32, - pub end: u32, - pub kind: AnnotationKind, +pub(crate) struct ConvertedAnnotation { + pub(crate) start: u32, + pub(crate) end: u32, + pub(crate) kind: AnnotationKind, } impl<'a> Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a> { - pub fn new(code: &'a str, annotations: &'a [AnnotationWithType]) -> Self { + pub(crate) fn new(code: &'a str, annotations: &'a [AnnotationWithType]) -> Self { let mut annotation_iterator = annotations.iter(); let current_annotation = annotation_iterator.next(); Self { @@ -62,7 +62,7 @@ impl<'a> Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a> { /// non-whitespace from the annotation, `keep_annotations_for_next` will /// prevent annotations from being invalidated when the next position is /// converted. - pub fn convert(&mut self, utf8_index: u32, keep_annotations_for_next: bool) -> u32 { + pub(crate) fn convert(&mut self, utf8_index: u32, keep_annotations_for_next: bool) -> u32 { if self.current_utf8_index > utf8_index { panic!( "Cannot convert positions backwards: {} < {}", @@ -108,7 +108,10 @@ impl<'a> Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a> { self.current_utf16_index } - pub fn take_collected_annotations(&mut self, kind: AnnotationKind) -> Vec { + pub(crate) fn take_collected_annotations( + &mut self, + kind: AnnotationKind, + ) -> Vec { let mut relevant_annotations = Vec::new(); for annotation in self.collected_annotations.drain(..) { if annotation.kind == kind { @@ -120,18 +123,18 @@ impl<'a> Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a> { relevant_annotations } - pub fn add_collected_annotations(&mut self, annotations: Vec) { + pub(crate) fn add_collected_annotations(&mut self, annotations: Vec) { self.collected_annotations.extend(annotations); self.keep_annotations = true; } - pub fn invalidate_collected_annotations(&mut self) { + pub(crate) fn invalidate_collected_annotations(&mut self) { self .invalid_annotations .append(&mut self.collected_annotations); } - pub fn take_invalid_annotations(&mut self) -> Vec { + pub(crate) fn take_invalid_annotations(&mut self) -> Vec { std::mem::take(&mut self.invalid_annotations) } } diff --git a/rust/parse_ast/src/error_emit.rs b/rust/parse_ast/src/error_emit.rs index 63ad66da21f..3b78c80aa51 100644 --- a/rust/parse_ast/src/error_emit.rs +++ b/rust/parse_ast/src/error_emit.rs @@ -2,7 +2,7 @@ use std::{io::Write, mem::take, sync::Arc}; use anyhow::Error; use parking_lot::Mutex; -use swc_common::errors::{DiagnosticBuilder, Emitter, Handler, Level, HANDLER}; +use swc_common::errors::{DiagnosticBuilder, Emitter, Handler, HANDLER, Level}; use swc_ecma_ast::Program; use crate::ast_nodes::parse_error::get_parse_error_buffer; @@ -24,7 +24,7 @@ impl Write for Writer { } } -pub struct ErrorEmitter { +pub(crate) struct ErrorEmitter { wr: Box, } @@ -44,7 +44,7 @@ impl Emitter for ErrorEmitter { } } -pub fn try_with_handler(code: &str, op: F) -> Result> +pub(crate) fn try_with_handler(code: &str, op: F) -> Result> where F: FnOnce(&Handler) -> Result, { From 8824ef572cb655ae7a86881937be07f9262182cd Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 2 Aug 2024 11:12:37 +0200 Subject: [PATCH 34/62] use macros for JSX where possible --- rust/parse_ast/src/ast_nodes/jsx_attribute.rs | 25 +- .../src/ast_nodes/jsx_closing_element.rs | 18 +- .../src/ast_nodes/jsx_closing_fragment.rs | 14 +- rust/parse_ast/src/ast_nodes/jsx_element.rs | 35 +- rust/parse_ast/src/ast_nodes/jsx_fragment.rs | 33 +- .../parse_ast/src/ast_nodes/jsx_identifier.rs | 17 +- .../src/ast_nodes/jsx_opening_fragment.rs | 16 +- .../src/ast_nodes/jsx_spread_child.rs | 18 +- rust/parse_ast/src/ast_nodes/jsx_text.rs | 20 +- rust/parse_ast/src/convert_ast/converter.rs | 6 +- .../convert_ast/converter/ast_constants.rs | 446 ++++++++---------- .../src/convert_ast/converter/ast_macros.rs | 134 ++++++ .../convert_ast/converter/string_constants.rs | 126 ++--- scripts/ast-types.js | 27 +- 14 files changed, 462 insertions(+), 473 deletions(-) diff --git a/rust/parse_ast/src/ast_nodes/jsx_attribute.rs b/rust/parse_ast/src/ast_nodes/jsx_attribute.rs index 25b12c86c34..1e36f231e8f 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_attribute.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_attribute.rs @@ -1,28 +1,15 @@ use swc_ecma_ast::JSXAttr; -use crate::convert_ast::converter::ast_constants::{ - JSX_ATTRIBUTE_NAME_OFFSET, JSX_ATTRIBUTE_RESERVED_BYTES, JSX_ATTRIBUTE_VALUE_OFFSET, - TYPE_JSX_ATTRIBUTE, -}; use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_attribute; impl<'a> AstConverter<'a> { pub(crate) fn store_jsx_attribute(&mut self, jsx_attribute: &JSXAttr) { - let end_position = self.add_type_and_start( - &TYPE_JSX_ATTRIBUTE, - &jsx_attribute.span, - JSX_ATTRIBUTE_RESERVED_BYTES, - false, + store_jsx_attribute!( + self, + span => jsx_attribute.span, + name => [jsx_attribute.name, convert_jsx_attribute_name], + value => [jsx_attribute.value, convert_jsx_attribute_value] ); - // name - self.update_reference_position(end_position + JSX_ATTRIBUTE_NAME_OFFSET); - self.convert_jsx_attribute_name(&jsx_attribute.name); - // value - if let Some(jsx_attribute_value) = jsx_attribute.value.as_ref() { - self.update_reference_position(end_position + JSX_ATTRIBUTE_VALUE_OFFSET); - self.convert_jsx_attribute_value(jsx_attribute_value); - }; - // end - self.add_end(end_position, &jsx_attribute.span); } } diff --git a/rust/parse_ast/src/ast_nodes/jsx_closing_element.rs b/rust/parse_ast/src/ast_nodes/jsx_closing_element.rs index c44c69b8fa8..c5281e50dcd 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_closing_element.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_closing_element.rs @@ -1,22 +1,14 @@ use swc_ecma_ast::JSXClosingElement; -use crate::convert_ast::converter::ast_constants::{ - JSX_CLOSING_ELEMENT_NAME_OFFSET, JSX_CLOSING_ELEMENT_RESERVED_BYTES, TYPE_JSX_CLOSING_ELEMENT, -}; use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_closing_element; impl<'a> AstConverter<'a> { pub(crate) fn store_jsx_closing_element(&mut self, jsx_closing_element: &JSXClosingElement) { - let end_position = self.add_type_and_start( - &TYPE_JSX_CLOSING_ELEMENT, - &jsx_closing_element.span, - JSX_CLOSING_ELEMENT_RESERVED_BYTES, - false, + store_jsx_closing_element!( + self, + span => jsx_closing_element.span, + name => [jsx_closing_element.name, convert_jsx_element_name] ); - // name - self.update_reference_position(end_position + JSX_CLOSING_ELEMENT_NAME_OFFSET); - self.convert_jsx_element_name(&jsx_closing_element.name); - // end - self.add_end(end_position, &jsx_closing_element.span); } } diff --git a/rust/parse_ast/src/ast_nodes/jsx_closing_fragment.rs b/rust/parse_ast/src/ast_nodes/jsx_closing_fragment.rs index 4c93b063852..650df600f1a 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_closing_fragment.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_closing_fragment.rs @@ -1,19 +1,13 @@ use swc_ecma_ast::JSXClosingFragment; -use crate::convert_ast::converter::ast_constants::{ - JSX_CLOSING_FRAGMENT_RESERVED_BYTES, TYPE_JSX_CLOSING_FRAGMENT, -}; use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_closing_fragment; impl<'a> AstConverter<'a> { pub(crate) fn store_jsx_closing_fragment(&mut self, jsx_closing_fragment: &JSXClosingFragment) { - let end_position = self.add_type_and_start( - &TYPE_JSX_CLOSING_FRAGMENT, - &jsx_closing_fragment.span, - JSX_CLOSING_FRAGMENT_RESERVED_BYTES, - false, + store_jsx_closing_fragment!( + self, + span => jsx_closing_fragment.span ); - // end - self.add_end(end_position, &jsx_closing_fragment.span); } } diff --git a/rust/parse_ast/src/ast_nodes/jsx_element.rs b/rust/parse_ast/src/ast_nodes/jsx_element.rs index 79c1912ab90..6a425940f2b 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_element.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_element.rs @@ -1,37 +1,16 @@ use swc_ecma_ast::JSXElement; -use crate::convert_ast::converter::ast_constants::{ - JSX_ELEMENT_CHILDREN_OFFSET, JSX_ELEMENT_CLOSING_ELEMENT_OFFSET, - JSX_ELEMENT_OPENING_ELEMENT_OFFSET, JSX_ELEMENT_RESERVED_BYTES, TYPE_JSX_ELEMENT, -}; use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_element; impl<'a> AstConverter<'a> { pub(crate) fn store_jsx_element(&mut self, jsx_element: &JSXElement) { - let end_position = self.add_type_and_start( - &TYPE_JSX_ELEMENT, - &jsx_element.span, - JSX_ELEMENT_RESERVED_BYTES, - false, + store_jsx_element!( + self, + span => jsx_element.span, + openingElement => [jsx_element.opening, store_jsx_opening_element], + children => [jsx_element.children, convert_jsx_element_child], + closingElement => [jsx_element.closing, store_jsx_closing_element] ); - // openingElement - self.update_reference_position(end_position + JSX_ELEMENT_OPENING_ELEMENT_OFFSET); - self.store_jsx_opening_element(&jsx_element.opening); - // children - self.convert_item_list( - &jsx_element.children, - end_position + JSX_ELEMENT_CHILDREN_OFFSET, - |ast_converter, jsx_element_child| { - ast_converter.convert_jsx_element_child(jsx_element_child); - true - }, - ); - // closingElement - if let Some(closing) = jsx_element.closing.as_ref() { - self.update_reference_position(end_position + JSX_ELEMENT_CLOSING_ELEMENT_OFFSET); - self.store_jsx_closing_element(closing); - } - // end - self.add_end(end_position, &jsx_element.span); } } diff --git a/rust/parse_ast/src/ast_nodes/jsx_fragment.rs b/rust/parse_ast/src/ast_nodes/jsx_fragment.rs index 8809ed43b29..0d7a19ded24 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_fragment.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_fragment.rs @@ -1,35 +1,16 @@ use swc_ecma_ast::JSXFragment; -use crate::convert_ast::converter::ast_constants::{ - JSX_FRAGMENT_CHILDREN_OFFSET, JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET, - JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET, JSX_FRAGMENT_RESERVED_BYTES, TYPE_JSX_FRAGMENT, -}; use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_fragment; impl<'a> AstConverter<'a> { pub(crate) fn store_jsx_fragment(&mut self, jsx_fragment: &JSXFragment) { - let end_position = self.add_type_and_start( - &TYPE_JSX_FRAGMENT, - &jsx_fragment.span, - JSX_FRAGMENT_RESERVED_BYTES, - false, + store_jsx_fragment!( + self, + span => jsx_fragment.span, + openingFragment => [jsx_fragment.opening, store_jsx_opening_fragment], + children => [jsx_fragment.children, convert_jsx_element_child], + closingFragment => [jsx_fragment.closing, store_jsx_closing_fragment] ); - // openingFragment - self.update_reference_position(end_position + JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET); - self.store_jsx_opening_fragment(jsx_fragment.opening); - // children - self.convert_item_list( - &jsx_fragment.children, - end_position + JSX_FRAGMENT_CHILDREN_OFFSET, - |ast_converter, jsx_element_child| { - ast_converter.convert_jsx_element_child(jsx_element_child); - true - }, - ); - // closingFragment - self.update_reference_position(end_position + JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET); - self.store_jsx_closing_fragment(&jsx_fragment.closing); - // end - self.add_end(end_position, &jsx_fragment.span); } } diff --git a/rust/parse_ast/src/ast_nodes/jsx_identifier.rs b/rust/parse_ast/src/ast_nodes/jsx_identifier.rs index 92e941b0d1e..0a3ba71c6cc 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_identifier.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_identifier.rs @@ -1,21 +1,14 @@ use swc_common::Span; -use crate::convert_ast::converter::ast_constants::{ - JSX_IDENTIFIER_NAME_OFFSET, JSX_IDENTIFIER_RESERVED_BYTES, TYPE_JSX_IDENTIFIER, -}; use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_identifier; impl<'a> AstConverter<'a> { pub(crate) fn store_jsx_identifier(&mut self, span: &Span, name: &str) { - let end_position = self.add_type_and_start( - &TYPE_JSX_IDENTIFIER, - span, - JSX_IDENTIFIER_RESERVED_BYTES, - false, + store_jsx_identifier!( + self, + span => span, + name => name ); - // name - self.convert_string(name, end_position + JSX_IDENTIFIER_NAME_OFFSET); - // end - self.add_end(end_position, span); } } diff --git a/rust/parse_ast/src/ast_nodes/jsx_opening_fragment.rs b/rust/parse_ast/src/ast_nodes/jsx_opening_fragment.rs index 5ec19e624c8..acb52da45ee 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_opening_fragment.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_opening_fragment.rs @@ -1,19 +1,13 @@ use swc_ecma_ast::JSXOpeningFragment; -use crate::convert_ast::converter::ast_constants::{ - JSX_OPENING_FRAGMENT_RESERVED_BYTES, TYPE_JSX_OPENING_FRAGMENT, -}; use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_opening_fragment; impl<'a> AstConverter<'a> { - pub(crate) fn store_jsx_opening_fragment(&mut self, jsxopening_fragment: JSXOpeningFragment) { - let end_position = self.add_type_and_start( - &TYPE_JSX_OPENING_FRAGMENT, - &jsxopening_fragment.span, - JSX_OPENING_FRAGMENT_RESERVED_BYTES, - false, + pub(crate) fn store_jsx_opening_fragment(&mut self, jsx_opening_fragment: &JSXOpeningFragment) { + store_jsx_opening_fragment!( + self, + span => jsx_opening_fragment.span ); - // end - self.add_end(end_position, &jsxopening_fragment.span); } } diff --git a/rust/parse_ast/src/ast_nodes/jsx_spread_child.rs b/rust/parse_ast/src/ast_nodes/jsx_spread_child.rs index 3b1c4ac795a..b65bc4961de 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_spread_child.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_spread_child.rs @@ -1,22 +1,14 @@ use swc_ecma_ast::JSXSpreadChild; -use crate::convert_ast::converter::ast_constants::{ - JSX_SPREAD_CHILD_EXPRESSION_OFFSET, JSX_SPREAD_CHILD_RESERVED_BYTES, TYPE_JSX_SPREAD_CHILD, -}; use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_spread_child; impl<'a> AstConverter<'a> { pub(crate) fn store_jsx_spread_child(&mut self, jsx_spread_child: &JSXSpreadChild) { - let end_position = self.add_type_and_start( - &TYPE_JSX_SPREAD_CHILD, - &jsx_spread_child.span, - JSX_SPREAD_CHILD_RESERVED_BYTES, - false, + store_jsx_spread_child!( + self, + span => jsx_spread_child.span, + expression => [jsx_spread_child.expr, convert_expression] ); - // expression - self.update_reference_position(end_position + JSX_SPREAD_CHILD_EXPRESSION_OFFSET); - self.convert_expression(&jsx_spread_child.expr); - // end - self.add_end(end_position, &jsx_spread_child.span); } } diff --git a/rust/parse_ast/src/ast_nodes/jsx_text.rs b/rust/parse_ast/src/ast_nodes/jsx_text.rs index 0d8d69e82d1..6bf72a1e34e 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_text.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_text.rs @@ -1,23 +1,15 @@ use swc_ecma_ast::JSXText; -use crate::convert_ast::converter::ast_constants::{ - JSX_TEXT_RAW_OFFSET, JSX_TEXT_RESERVED_BYTES, JSX_TEXT_VALUE_OFFSET, TYPE_JSX_TEXT, -}; use crate::convert_ast::converter::AstConverter; +use crate::store_jsx_text; impl<'a> AstConverter<'a> { pub(crate) fn store_jsx_text(&mut self, jsx_text: &JSXText) { - let end_position = self.add_type_and_start( - &TYPE_JSX_TEXT, - &jsx_text.span, - JSX_TEXT_RESERVED_BYTES, - false, + store_jsx_text!( + self, + span => jsx_text.span, + value => &jsx_text.value, + raw => &jsx_text.raw ); - // value - self.convert_string(&jsx_text.value, end_position + JSX_TEXT_VALUE_OFFSET); - // raw - self.convert_string(&jsx_text.raw, end_position + JSX_TEXT_RAW_OFFSET); - // end - self.add_end(end_position, &jsx_text.span); } } diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 29f9cdb4cbe..92f8a345a4a 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -2,9 +2,9 @@ use swc_common::Span; use swc_ecma_ast::{ AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, ExprOrSpread, ForHead, ImportSpecifier, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, - JSXElementChild, JSXElementName, JSXObject, Lit, ModuleDecl, ModuleExportName, ModuleItem, - NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, - SimpleAssignTarget, Stmt, VarDeclOrExpr, + JSXElementChild, JSXElementName, JSXObject, Lit, ModuleDecl, ModuleExportName, + ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, + PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs index d8334614f0b..add6ddf81e8 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_constants.rs @@ -1,248 +1,208 @@ // This file is generated by scripts/generate-rust-constants.js. // Do not edit this file directly. -pub(crate) const TYPE_PANIC_ERROR: [u8; 4] = 0u32.to_ne_bytes(); -pub(crate) const TYPE_PARSE_ERROR: [u8; 4] = 1u32.to_ne_bytes(); -pub(crate) const TYPE_ARRAY_EXPRESSION: [u8; 4] = 2u32.to_ne_bytes(); -pub(crate) const TYPE_ARRAY_PATTERN: [u8; 4] = 3u32.to_ne_bytes(); -pub(crate) const TYPE_ARROW_FUNCTION_EXPRESSION: [u8; 4] = 4u32.to_ne_bytes(); -pub(crate) const TYPE_ASSIGNMENT_PATTERN: [u8; 4] = 6u32.to_ne_bytes(); -pub(crate) const TYPE_BINARY_EXPRESSION: [u8; 4] = 8u32.to_ne_bytes(); -pub(crate) const TYPE_BLOCK_STATEMENT: [u8; 4] = 9u32.to_ne_bytes(); -pub(crate) const TYPE_CALL_EXPRESSION: [u8; 4] = 11u32.to_ne_bytes(); -pub(crate) const TYPE_CATCH_CLAUSE: [u8; 4] = 12u32.to_ne_bytes(); -pub(crate) const TYPE_CHAIN_EXPRESSION: [u8; 4] = 13u32.to_ne_bytes(); -pub(crate) const TYPE_CLASS_BODY: [u8; 4] = 14u32.to_ne_bytes(); -pub(crate) const TYPE_CLASS_DECLARATION: [u8; 4] = 15u32.to_ne_bytes(); -pub(crate) const TYPE_CLASS_EXPRESSION: [u8; 4] = 16u32.to_ne_bytes(); -pub(crate) const TYPE_EXPORT_ALL_DECLARATION: [u8; 4] = 24u32.to_ne_bytes(); -pub(crate) const TYPE_EXPORT_DEFAULT_DECLARATION: [u8; 4] = 25u32.to_ne_bytes(); -pub(crate) const TYPE_EXPORT_NAMED_DECLARATION: [u8; 4] = 26u32.to_ne_bytes(); -pub(crate) const TYPE_FUNCTION_DECLARATION: [u8; 4] = 32u32.to_ne_bytes(); -pub(crate) const TYPE_FUNCTION_EXPRESSION: [u8; 4] = 33u32.to_ne_bytes(); -pub(crate) const TYPE_IDENTIFIER: [u8; 4] = 34u32.to_ne_bytes(); -pub(crate) const TYPE_IMPORT_ATTRIBUTE: [u8; 4] = 36u32.to_ne_bytes(); -pub(crate) const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); -pub(crate) const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_ATTRIBUTE: [u8; 4] = 42u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_CLOSING_ELEMENT: [u8; 4] = 43u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_CLOSING_FRAGMENT: [u8; 4] = 44u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_ELEMENT: [u8; 4] = 45u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_EMPTY_EXPRESSION: [u8; 4] = 46u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_EXPRESSION_CONTAINER: [u8; 4] = 47u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_FRAGMENT: [u8; 4] = 48u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_IDENTIFIER: [u8; 4] = 49u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_MEMBER_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_NAMESPACED_NAME: [u8; 4] = 51u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 52u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_OPENING_FRAGMENT: [u8; 4] = 53u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_SPREAD_ATTRIBUTE: [u8; 4] = 54u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_SPREAD_CHILD: [u8; 4] = 55u32.to_ne_bytes(); -pub(crate) const TYPE_JSX_TEXT: [u8; 4] = 56u32.to_ne_bytes(); -pub(crate) const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 64u32.to_ne_bytes(); -pub(crate) const TYPE_MEMBER_EXPRESSION: [u8; 4] = 65u32.to_ne_bytes(); -pub(crate) const TYPE_META_PROPERTY: [u8; 4] = 66u32.to_ne_bytes(); -pub(crate) const TYPE_METHOD_DEFINITION: [u8; 4] = 67u32.to_ne_bytes(); -pub(crate) const TYPE_NEW_EXPRESSION: [u8; 4] = 68u32.to_ne_bytes(); -pub(crate) const TYPE_PROGRAM: [u8; 4] = 72u32.to_ne_bytes(); -pub(crate) const TYPE_PROPERTY: [u8; 4] = 73u32.to_ne_bytes(); -pub(crate) const TYPE_PROPERTY_DEFINITION: [u8; 4] = 74u32.to_ne_bytes(); -pub(crate) const TYPE_REST_ELEMENT: [u8; 4] = 75u32.to_ne_bytes(); -pub(crate) const TYPE_SPREAD_ELEMENT: [u8; 4] = 78u32.to_ne_bytes(); -pub(crate) const TYPE_TEMPLATE_LITERAL: [u8; 4] = 85u32.to_ne_bytes(); -pub(crate) const TYPE_TRY_STATEMENT: [u8; 4] = 88u32.to_ne_bytes(); -pub(crate) const TYPE_VARIABLE_DECLARATION: [u8; 4] = 91u32.to_ne_bytes(); -pub(crate) const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 92u32.to_ne_bytes(); - -pub(crate) const PANIC_ERROR_RESERVED_BYTES: usize = 8; -pub(crate) const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; - -pub(crate) const PARSE_ERROR_RESERVED_BYTES: usize = 8; -pub(crate) const PARSE_ERROR_MESSAGE_OFFSET: usize = 4; - -pub(crate) const ARRAY_EXPRESSION_RESERVED_BYTES: usize = 8; -pub(crate) const ARRAY_EXPRESSION_ELEMENTS_OFFSET: usize = 4; - -pub(crate) const ARRAY_PATTERN_RESERVED_BYTES: usize = 8; -pub(crate) const ARRAY_PATTERN_ELEMENTS_OFFSET: usize = 4; - -pub(crate) const ARROW_FUNCTION_EXPRESSION_RESERVED_BYTES: usize = 20; -pub(crate) const ARROW_FUNCTION_EXPRESSION_ANNOTATIONS_OFFSET: usize = 8; -pub(crate) const ARROW_FUNCTION_EXPRESSION_PARAMS_OFFSET: usize = 12; -pub(crate) const ARROW_FUNCTION_EXPRESSION_BODY_OFFSET: usize = 16; - -pub(crate) const ASSIGNMENT_PATTERN_RESERVED_BYTES: usize = 12; -pub(crate) const ASSIGNMENT_PATTERN_LEFT_OFFSET: usize = 4; -pub(crate) const ASSIGNMENT_PATTERN_RIGHT_OFFSET: usize = 8; - -pub(crate) const BINARY_EXPRESSION_RESERVED_BYTES: usize = 16; -pub(crate) const BINARY_EXPRESSION_OPERATOR_OFFSET: usize = 4; -pub(crate) const BINARY_EXPRESSION_LEFT_OFFSET: usize = 8; -pub(crate) const BINARY_EXPRESSION_RIGHT_OFFSET: usize = 12; - -pub(crate) const BLOCK_STATEMENT_RESERVED_BYTES: usize = 8; -pub(crate) const BLOCK_STATEMENT_BODY_OFFSET: usize = 4; - -pub(crate) const CALL_EXPRESSION_RESERVED_BYTES: usize = 20; -pub(crate) const CALL_EXPRESSION_ANNOTATIONS_OFFSET: usize = 8; -pub(crate) const CALL_EXPRESSION_CALLEE_OFFSET: usize = 12; -pub(crate) const CALL_EXPRESSION_ARGUMENTS_OFFSET: usize = 16; - -pub(crate) const CATCH_CLAUSE_RESERVED_BYTES: usize = 12; -pub(crate) const CATCH_CLAUSE_PARAM_OFFSET: usize = 4; -pub(crate) const CATCH_CLAUSE_BODY_OFFSET: usize = 8; - -pub(crate) const CHAIN_EXPRESSION_RESERVED_BYTES: usize = 8; -pub(crate) const CHAIN_EXPRESSION_EXPRESSION_OFFSET: usize = 4; - -pub(crate) const CLASS_BODY_RESERVED_BYTES: usize = 8; -pub(crate) const CLASS_BODY_BODY_OFFSET: usize = 4; - -pub(crate) const CLASS_DECLARATION_RESERVED_BYTES: usize = 20; -pub(crate) const CLASS_DECLARATION_DECORATORS_OFFSET: usize = 4; -pub(crate) const CLASS_DECLARATION_ID_OFFSET: usize = 8; -pub(crate) const CLASS_DECLARATION_SUPER_CLASS_OFFSET: usize = 12; -pub(crate) const CLASS_DECLARATION_BODY_OFFSET: usize = 16; - -pub(crate) const EXPORT_ALL_DECLARATION_RESERVED_BYTES: usize = 16; -pub(crate) const EXPORT_ALL_DECLARATION_EXPORTED_OFFSET: usize = 4; -pub(crate) const EXPORT_ALL_DECLARATION_SOURCE_OFFSET: usize = 8; -pub(crate) const EXPORT_ALL_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; - -pub(crate) const EXPORT_DEFAULT_DECLARATION_RESERVED_BYTES: usize = 8; -pub(crate) const EXPORT_DEFAULT_DECLARATION_DECLARATION_OFFSET: usize = 4; - -pub(crate) const EXPORT_NAMED_DECLARATION_RESERVED_BYTES: usize = 20; -pub(crate) const EXPORT_NAMED_DECLARATION_SPECIFIERS_OFFSET: usize = 4; -pub(crate) const EXPORT_NAMED_DECLARATION_SOURCE_OFFSET: usize = 8; -pub(crate) const EXPORT_NAMED_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; -pub(crate) const EXPORT_NAMED_DECLARATION_DECLARATION_OFFSET: usize = 16; - -pub(crate) const FUNCTION_DECLARATION_RESERVED_BYTES: usize = 24; -pub(crate) const FUNCTION_DECLARATION_ANNOTATIONS_OFFSET: usize = 8; -pub(crate) const FUNCTION_DECLARATION_ID_OFFSET: usize = 12; -pub(crate) const FUNCTION_DECLARATION_PARAMS_OFFSET: usize = 16; -pub(crate) const FUNCTION_DECLARATION_BODY_OFFSET: usize = 20; - -pub(crate) const IDENTIFIER_RESERVED_BYTES: usize = 8; -pub(crate) const IDENTIFIER_NAME_OFFSET: usize = 4; - -pub(crate) const IMPORT_ATTRIBUTE_RESERVED_BYTES: usize = 12; -pub(crate) const IMPORT_ATTRIBUTE_KEY_OFFSET: usize = 4; -pub(crate) const IMPORT_ATTRIBUTE_VALUE_OFFSET: usize = 8; - -pub(crate) const IMPORT_DECLARATION_RESERVED_BYTES: usize = 16; -pub(crate) const IMPORT_DECLARATION_SPECIFIERS_OFFSET: usize = 4; -pub(crate) const IMPORT_DECLARATION_SOURCE_OFFSET: usize = 8; -pub(crate) const IMPORT_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; - -pub(crate) const IMPORT_EXPRESSION_RESERVED_BYTES: usize = 12; -pub(crate) const IMPORT_EXPRESSION_SOURCE_OFFSET: usize = 4; -pub(crate) const IMPORT_EXPRESSION_OPTIONS_OFFSET: usize = 8; - -pub(crate) const JSX_ATTRIBUTE_RESERVED_BYTES: usize = 12; -pub(crate) const JSX_ATTRIBUTE_NAME_OFFSET: usize = 4; -pub(crate) const JSX_ATTRIBUTE_VALUE_OFFSET: usize = 8; - -pub(crate) const JSX_CLOSING_ELEMENT_RESERVED_BYTES: usize = 8; -pub(crate) const JSX_CLOSING_ELEMENT_NAME_OFFSET: usize = 4; - -pub(crate) const JSX_CLOSING_FRAGMENT_RESERVED_BYTES: usize = 4; +pub const TYPE_PANIC_ERROR: [u8; 4] = 0u32.to_ne_bytes(); +pub const TYPE_PARSE_ERROR: [u8; 4] = 1u32.to_ne_bytes(); +pub const TYPE_ARRAY_EXPRESSION: [u8; 4] = 2u32.to_ne_bytes(); +pub const TYPE_ARRAY_PATTERN: [u8; 4] = 3u32.to_ne_bytes(); +pub const TYPE_ARROW_FUNCTION_EXPRESSION: [u8; 4] = 4u32.to_ne_bytes(); +pub const TYPE_ASSIGNMENT_PATTERN: [u8; 4] = 6u32.to_ne_bytes(); +pub const TYPE_BINARY_EXPRESSION: [u8; 4] = 8u32.to_ne_bytes(); +pub const TYPE_BLOCK_STATEMENT: [u8; 4] = 9u32.to_ne_bytes(); +pub const TYPE_CALL_EXPRESSION: [u8; 4] = 11u32.to_ne_bytes(); +pub const TYPE_CATCH_CLAUSE: [u8; 4] = 12u32.to_ne_bytes(); +pub const TYPE_CHAIN_EXPRESSION: [u8; 4] = 13u32.to_ne_bytes(); +pub const TYPE_CLASS_BODY: [u8; 4] = 14u32.to_ne_bytes(); +pub const TYPE_CLASS_DECLARATION: [u8; 4] = 15u32.to_ne_bytes(); +pub const TYPE_CLASS_EXPRESSION: [u8; 4] = 16u32.to_ne_bytes(); +pub const TYPE_EXPORT_ALL_DECLARATION: [u8; 4] = 24u32.to_ne_bytes(); +pub const TYPE_EXPORT_DEFAULT_DECLARATION: [u8; 4] = 25u32.to_ne_bytes(); +pub const TYPE_EXPORT_NAMED_DECLARATION: [u8; 4] = 26u32.to_ne_bytes(); +pub const TYPE_FUNCTION_DECLARATION: [u8; 4] = 32u32.to_ne_bytes(); +pub const TYPE_FUNCTION_EXPRESSION: [u8; 4] = 33u32.to_ne_bytes(); +pub const TYPE_IDENTIFIER: [u8; 4] = 34u32.to_ne_bytes(); +pub const TYPE_IMPORT_ATTRIBUTE: [u8; 4] = 36u32.to_ne_bytes(); +pub const TYPE_IMPORT_DECLARATION: [u8; 4] = 37u32.to_ne_bytes(); +pub const TYPE_IMPORT_EXPRESSION: [u8; 4] = 39u32.to_ne_bytes(); +pub const TYPE_JSX_EMPTY_EXPRESSION: [u8; 4] = 46u32.to_ne_bytes(); +pub const TYPE_JSX_EXPRESSION_CONTAINER: [u8; 4] = 47u32.to_ne_bytes(); +pub const TYPE_JSX_MEMBER_EXPRESSION: [u8; 4] = 50u32.to_ne_bytes(); +pub const TYPE_JSX_NAMESPACED_NAME: [u8; 4] = 51u32.to_ne_bytes(); +pub const TYPE_JSX_OPENING_ELEMENT: [u8; 4] = 52u32.to_ne_bytes(); +pub const TYPE_JSX_SPREAD_ATTRIBUTE: [u8; 4] = 54u32.to_ne_bytes(); +pub const TYPE_LOGICAL_EXPRESSION: [u8; 4] = 64u32.to_ne_bytes(); +pub const TYPE_MEMBER_EXPRESSION: [u8; 4] = 65u32.to_ne_bytes(); +pub const TYPE_META_PROPERTY: [u8; 4] = 66u32.to_ne_bytes(); +pub const TYPE_METHOD_DEFINITION: [u8; 4] = 67u32.to_ne_bytes(); +pub const TYPE_NEW_EXPRESSION: [u8; 4] = 68u32.to_ne_bytes(); +pub const TYPE_PROGRAM: [u8; 4] = 72u32.to_ne_bytes(); +pub const TYPE_PROPERTY: [u8; 4] = 73u32.to_ne_bytes(); +pub const TYPE_PROPERTY_DEFINITION: [u8; 4] = 74u32.to_ne_bytes(); +pub const TYPE_REST_ELEMENT: [u8; 4] = 75u32.to_ne_bytes(); +pub const TYPE_SPREAD_ELEMENT: [u8; 4] = 78u32.to_ne_bytes(); +pub const TYPE_TEMPLATE_LITERAL: [u8; 4] = 85u32.to_ne_bytes(); +pub const TYPE_TRY_STATEMENT: [u8; 4] = 88u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATION: [u8; 4] = 91u32.to_ne_bytes(); +pub const TYPE_VARIABLE_DECLARATOR: [u8; 4] = 92u32.to_ne_bytes(); + +pub const PANIC_ERROR_RESERVED_BYTES: usize = 8; +pub const PANIC_ERROR_MESSAGE_OFFSET: usize = 4; + +pub const PARSE_ERROR_RESERVED_BYTES: usize = 8; +pub const PARSE_ERROR_MESSAGE_OFFSET: usize = 4; + +pub const ARRAY_EXPRESSION_RESERVED_BYTES: usize = 8; +pub const ARRAY_EXPRESSION_ELEMENTS_OFFSET: usize = 4; + +pub const ARRAY_PATTERN_RESERVED_BYTES: usize = 8; +pub const ARRAY_PATTERN_ELEMENTS_OFFSET: usize = 4; + +pub const ARROW_FUNCTION_EXPRESSION_RESERVED_BYTES: usize = 20; +pub const ARROW_FUNCTION_EXPRESSION_ANNOTATIONS_OFFSET: usize = 8; +pub const ARROW_FUNCTION_EXPRESSION_PARAMS_OFFSET: usize = 12; +pub const ARROW_FUNCTION_EXPRESSION_BODY_OFFSET: usize = 16; + +pub const ASSIGNMENT_PATTERN_RESERVED_BYTES: usize = 12; +pub const ASSIGNMENT_PATTERN_LEFT_OFFSET: usize = 4; +pub const ASSIGNMENT_PATTERN_RIGHT_OFFSET: usize = 8; + +pub const BINARY_EXPRESSION_RESERVED_BYTES: usize = 16; +pub const BINARY_EXPRESSION_OPERATOR_OFFSET: usize = 4; +pub const BINARY_EXPRESSION_LEFT_OFFSET: usize = 8; +pub const BINARY_EXPRESSION_RIGHT_OFFSET: usize = 12; + +pub const BLOCK_STATEMENT_RESERVED_BYTES: usize = 8; +pub const BLOCK_STATEMENT_BODY_OFFSET: usize = 4; + +pub const CALL_EXPRESSION_RESERVED_BYTES: usize = 20; +pub const CALL_EXPRESSION_ANNOTATIONS_OFFSET: usize = 8; +pub const CALL_EXPRESSION_CALLEE_OFFSET: usize = 12; +pub const CALL_EXPRESSION_ARGUMENTS_OFFSET: usize = 16; + +pub const CATCH_CLAUSE_RESERVED_BYTES: usize = 12; +pub const CATCH_CLAUSE_PARAM_OFFSET: usize = 4; +pub const CATCH_CLAUSE_BODY_OFFSET: usize = 8; + +pub const CHAIN_EXPRESSION_RESERVED_BYTES: usize = 8; +pub const CHAIN_EXPRESSION_EXPRESSION_OFFSET: usize = 4; + +pub const CLASS_BODY_RESERVED_BYTES: usize = 8; +pub const CLASS_BODY_BODY_OFFSET: usize = 4; + +pub const CLASS_DECLARATION_RESERVED_BYTES: usize = 20; +pub const CLASS_DECLARATION_DECORATORS_OFFSET: usize = 4; +pub const CLASS_DECLARATION_ID_OFFSET: usize = 8; +pub const CLASS_DECLARATION_SUPER_CLASS_OFFSET: usize = 12; +pub const CLASS_DECLARATION_BODY_OFFSET: usize = 16; + +pub const EXPORT_ALL_DECLARATION_RESERVED_BYTES: usize = 16; +pub const EXPORT_ALL_DECLARATION_EXPORTED_OFFSET: usize = 4; +pub const EXPORT_ALL_DECLARATION_SOURCE_OFFSET: usize = 8; +pub const EXPORT_ALL_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; + +pub const EXPORT_DEFAULT_DECLARATION_RESERVED_BYTES: usize = 8; +pub const EXPORT_DEFAULT_DECLARATION_DECLARATION_OFFSET: usize = 4; + +pub const EXPORT_NAMED_DECLARATION_RESERVED_BYTES: usize = 20; +pub const EXPORT_NAMED_DECLARATION_SPECIFIERS_OFFSET: usize = 4; +pub const EXPORT_NAMED_DECLARATION_SOURCE_OFFSET: usize = 8; +pub const EXPORT_NAMED_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; +pub const EXPORT_NAMED_DECLARATION_DECLARATION_OFFSET: usize = 16; + +pub const FUNCTION_DECLARATION_RESERVED_BYTES: usize = 24; +pub const FUNCTION_DECLARATION_ANNOTATIONS_OFFSET: usize = 8; +pub const FUNCTION_DECLARATION_ID_OFFSET: usize = 12; +pub const FUNCTION_DECLARATION_PARAMS_OFFSET: usize = 16; +pub const FUNCTION_DECLARATION_BODY_OFFSET: usize = 20; + +pub const IDENTIFIER_RESERVED_BYTES: usize = 8; +pub const IDENTIFIER_NAME_OFFSET: usize = 4; + +pub const IMPORT_ATTRIBUTE_RESERVED_BYTES: usize = 12; +pub const IMPORT_ATTRIBUTE_KEY_OFFSET: usize = 4; +pub const IMPORT_ATTRIBUTE_VALUE_OFFSET: usize = 8; + +pub const IMPORT_DECLARATION_RESERVED_BYTES: usize = 16; +pub const IMPORT_DECLARATION_SPECIFIERS_OFFSET: usize = 4; +pub const IMPORT_DECLARATION_SOURCE_OFFSET: usize = 8; +pub const IMPORT_DECLARATION_ATTRIBUTES_OFFSET: usize = 12; + +pub const IMPORT_EXPRESSION_RESERVED_BYTES: usize = 12; +pub const IMPORT_EXPRESSION_SOURCE_OFFSET: usize = 4; +pub const IMPORT_EXPRESSION_OPTIONS_OFFSET: usize = 8; + +pub const JSX_EMPTY_EXPRESSION_RESERVED_BYTES: usize = 4; + +pub const JSX_EXPRESSION_CONTAINER_RESERVED_BYTES: usize = 8; +pub const JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET: usize = 4; + +pub const JSX_MEMBER_EXPRESSION_RESERVED_BYTES: usize = 12; +pub const JSX_MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 4; +pub const JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 8; + +pub const JSX_NAMESPACED_NAME_RESERVED_BYTES: usize = 12; +pub const JSX_NAMESPACED_NAME_NAMESPACE_OFFSET: usize = 4; +pub const JSX_NAMESPACED_NAME_NAME_OFFSET: usize = 8; -pub(crate) const JSX_ELEMENT_RESERVED_BYTES: usize = 16; -pub(crate) const JSX_ELEMENT_OPENING_ELEMENT_OFFSET: usize = 4; -pub(crate) const JSX_ELEMENT_CHILDREN_OFFSET: usize = 8; -pub(crate) const JSX_ELEMENT_CLOSING_ELEMENT_OFFSET: usize = 12; +pub const JSX_OPENING_ELEMENT_RESERVED_BYTES: usize = 16; +pub const JSX_OPENING_ELEMENT_NAME_OFFSET: usize = 8; +pub const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; -pub(crate) const JSX_EMPTY_EXPRESSION_RESERVED_BYTES: usize = 4; - -pub(crate) const JSX_EXPRESSION_CONTAINER_RESERVED_BYTES: usize = 8; -pub(crate) const JSX_EXPRESSION_CONTAINER_EXPRESSION_OFFSET: usize = 4; - -pub(crate) const JSX_FRAGMENT_RESERVED_BYTES: usize = 16; -pub(crate) const JSX_FRAGMENT_OPENING_FRAGMENT_OFFSET: usize = 4; -pub(crate) const JSX_FRAGMENT_CHILDREN_OFFSET: usize = 8; -pub(crate) const JSX_FRAGMENT_CLOSING_FRAGMENT_OFFSET: usize = 12; - -pub(crate) const JSX_IDENTIFIER_RESERVED_BYTES: usize = 8; -pub(crate) const JSX_IDENTIFIER_NAME_OFFSET: usize = 4; - -pub(crate) const JSX_MEMBER_EXPRESSION_RESERVED_BYTES: usize = 12; -pub(crate) const JSX_MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 4; -pub(crate) const JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 8; - -pub(crate) const JSX_NAMESPACED_NAME_RESERVED_BYTES: usize = 12; -pub(crate) const JSX_NAMESPACED_NAME_NAMESPACE_OFFSET: usize = 4; -pub(crate) const JSX_NAMESPACED_NAME_NAME_OFFSET: usize = 8; - -pub(crate) const JSX_OPENING_ELEMENT_RESERVED_BYTES: usize = 16; -pub(crate) const JSX_OPENING_ELEMENT_NAME_OFFSET: usize = 8; -pub(crate) const JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET: usize = 12; - -pub(crate) const JSX_OPENING_FRAGMENT_RESERVED_BYTES: usize = 4; - -pub(crate) const JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES: usize = 8; -pub(crate) const JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET: usize = 4; - -pub(crate) const JSX_SPREAD_CHILD_RESERVED_BYTES: usize = 8; -pub(crate) const JSX_SPREAD_CHILD_EXPRESSION_OFFSET: usize = 4; - -pub(crate) const JSX_TEXT_RESERVED_BYTES: usize = 12; -pub(crate) const JSX_TEXT_VALUE_OFFSET: usize = 4; -pub(crate) const JSX_TEXT_RAW_OFFSET: usize = 8; - -pub(crate) const MEMBER_EXPRESSION_RESERVED_BYTES: usize = 16; -pub(crate) const MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 8; -pub(crate) const MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 12; - -pub(crate) const META_PROPERTY_RESERVED_BYTES: usize = 12; -pub(crate) const META_PROPERTY_META_OFFSET: usize = 4; -pub(crate) const META_PROPERTY_PROPERTY_OFFSET: usize = 8; - -pub(crate) const METHOD_DEFINITION_RESERVED_BYTES: usize = 24; -pub(crate) const METHOD_DEFINITION_DECORATORS_OFFSET: usize = 8; -pub(crate) const METHOD_DEFINITION_KEY_OFFSET: usize = 12; -pub(crate) const METHOD_DEFINITION_VALUE_OFFSET: usize = 16; -pub(crate) const METHOD_DEFINITION_KIND_OFFSET: usize = 20; - -pub(crate) const NEW_EXPRESSION_RESERVED_BYTES: usize = 16; -pub(crate) const NEW_EXPRESSION_ANNOTATIONS_OFFSET: usize = 4; -pub(crate) const NEW_EXPRESSION_CALLEE_OFFSET: usize = 8; -pub(crate) const NEW_EXPRESSION_ARGUMENTS_OFFSET: usize = 12; - -pub(crate) const PROGRAM_RESERVED_BYTES: usize = 12; -pub(crate) const PROGRAM_BODY_OFFSET: usize = 4; -pub(crate) const PROGRAM_INVALID_ANNOTATIONS_OFFSET: usize = 8; - -pub(crate) const PROPERTY_RESERVED_BYTES: usize = 20; -pub(crate) const PROPERTY_KEY_OFFSET: usize = 8; -pub(crate) const PROPERTY_VALUE_OFFSET: usize = 12; -pub(crate) const PROPERTY_KIND_OFFSET: usize = 16; - -pub(crate) const PROPERTY_DEFINITION_RESERVED_BYTES: usize = 20; -pub(crate) const PROPERTY_DEFINITION_DECORATORS_OFFSET: usize = 8; -pub(crate) const PROPERTY_DEFINITION_KEY_OFFSET: usize = 12; -pub(crate) const PROPERTY_DEFINITION_VALUE_OFFSET: usize = 16; - -pub(crate) const REST_ELEMENT_RESERVED_BYTES: usize = 8; -pub(crate) const REST_ELEMENT_ARGUMENT_OFFSET: usize = 4; - -pub(crate) const SPREAD_ELEMENT_RESERVED_BYTES: usize = 8; -pub(crate) const SPREAD_ELEMENT_ARGUMENT_OFFSET: usize = 4; - -pub(crate) const TEMPLATE_LITERAL_RESERVED_BYTES: usize = 12; -pub(crate) const TEMPLATE_LITERAL_QUASIS_OFFSET: usize = 4; -pub(crate) const TEMPLATE_LITERAL_EXPRESSIONS_OFFSET: usize = 8; - -pub(crate) const TRY_STATEMENT_RESERVED_BYTES: usize = 16; -pub(crate) const TRY_STATEMENT_BLOCK_OFFSET: usize = 4; -pub(crate) const TRY_STATEMENT_HANDLER_OFFSET: usize = 8; -pub(crate) const TRY_STATEMENT_FINALIZER_OFFSET: usize = 12; - -pub(crate) const VARIABLE_DECLARATION_RESERVED_BYTES: usize = 12; -pub(crate) const VARIABLE_DECLARATION_KIND_OFFSET: usize = 4; -pub(crate) const VARIABLE_DECLARATION_DECLARATIONS_OFFSET: usize = 8; - -pub(crate) const VARIABLE_DECLARATOR_RESERVED_BYTES: usize = 12; -pub(crate) const VARIABLE_DECLARATOR_ID_OFFSET: usize = 4; -pub(crate) const VARIABLE_DECLARATOR_INIT_OFFSET: usize = 8; +pub const JSX_SPREAD_ATTRIBUTE_RESERVED_BYTES: usize = 8; +pub const JSX_SPREAD_ATTRIBUTE_ARGUMENT_OFFSET: usize = 4; + +pub const MEMBER_EXPRESSION_RESERVED_BYTES: usize = 16; +pub const MEMBER_EXPRESSION_OBJECT_OFFSET: usize = 8; +pub const MEMBER_EXPRESSION_PROPERTY_OFFSET: usize = 12; + +pub const META_PROPERTY_RESERVED_BYTES: usize = 12; +pub const META_PROPERTY_META_OFFSET: usize = 4; +pub const META_PROPERTY_PROPERTY_OFFSET: usize = 8; + +pub const METHOD_DEFINITION_RESERVED_BYTES: usize = 24; +pub const METHOD_DEFINITION_DECORATORS_OFFSET: usize = 8; +pub const METHOD_DEFINITION_KEY_OFFSET: usize = 12; +pub const METHOD_DEFINITION_VALUE_OFFSET: usize = 16; +pub const METHOD_DEFINITION_KIND_OFFSET: usize = 20; + +pub const NEW_EXPRESSION_RESERVED_BYTES: usize = 16; +pub const NEW_EXPRESSION_ANNOTATIONS_OFFSET: usize = 4; +pub const NEW_EXPRESSION_CALLEE_OFFSET: usize = 8; +pub const NEW_EXPRESSION_ARGUMENTS_OFFSET: usize = 12; + +pub const PROGRAM_RESERVED_BYTES: usize = 12; +pub const PROGRAM_BODY_OFFSET: usize = 4; +pub const PROGRAM_INVALID_ANNOTATIONS_OFFSET: usize = 8; + +pub const PROPERTY_RESERVED_BYTES: usize = 20; +pub const PROPERTY_KEY_OFFSET: usize = 8; +pub const PROPERTY_VALUE_OFFSET: usize = 12; +pub const PROPERTY_KIND_OFFSET: usize = 16; + +pub const PROPERTY_DEFINITION_RESERVED_BYTES: usize = 20; +pub const PROPERTY_DEFINITION_DECORATORS_OFFSET: usize = 8; +pub const PROPERTY_DEFINITION_KEY_OFFSET: usize = 12; +pub const PROPERTY_DEFINITION_VALUE_OFFSET: usize = 16; + +pub const REST_ELEMENT_RESERVED_BYTES: usize = 8; +pub const REST_ELEMENT_ARGUMENT_OFFSET: usize = 4; + +pub const SPREAD_ELEMENT_RESERVED_BYTES: usize = 8; +pub const SPREAD_ELEMENT_ARGUMENT_OFFSET: usize = 4; + +pub const TEMPLATE_LITERAL_RESERVED_BYTES: usize = 12; +pub const TEMPLATE_LITERAL_QUASIS_OFFSET: usize = 4; +pub const TEMPLATE_LITERAL_EXPRESSIONS_OFFSET: usize = 8; + +pub const TRY_STATEMENT_RESERVED_BYTES: usize = 16; +pub const TRY_STATEMENT_BLOCK_OFFSET: usize = 4; +pub const TRY_STATEMENT_HANDLER_OFFSET: usize = 8; +pub const TRY_STATEMENT_FINALIZER_OFFSET: usize = 12; + +pub const VARIABLE_DECLARATION_RESERVED_BYTES: usize = 12; +pub const VARIABLE_DECLARATION_KIND_OFFSET: usize = 4; +pub const VARIABLE_DECLARATION_DECLARATIONS_OFFSET: usize = 8; + +pub const VARIABLE_DECLARATOR_RESERVED_BYTES: usize = 12; +pub const VARIABLE_DECLARATOR_ID_OFFSET: usize = 4; +pub const VARIABLE_DECLARATOR_INIT_OFFSET: usize = 8; diff --git a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs index 324ee8294f8..84fff18bf9a 100644 --- a/rust/parse_ast/src/convert_ast/converter/ast_macros.rs +++ b/rust/parse_ast/src/convert_ast/converter/ast_macros.rs @@ -315,6 +315,140 @@ macro_rules! store_import_specifier { }; } +#[macro_export] +macro_rules! store_jsx_attribute { + ($self:expr, span => $span:expr, name => [$name_value:expr, $name_converter:ident], value => [$value_value:expr, $value_converter:ident]) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&42u32.to_ne_bytes(), &$span, 12, false); + // name + $self.update_reference_position(end_position + 4); + $self.$name_converter(&$name_value); + // value + if let Some(value) = $value_value.as_ref() { + $self.update_reference_position(end_position + 8); + $self.$value_converter(value); + } + // end + $self.add_end(end_position, &$span); + }; +} + +#[macro_export] +macro_rules! store_jsx_closing_element { + ($self:expr, span => $span:expr, name => [$name_value:expr, $name_converter:ident]) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&43u32.to_ne_bytes(), &$span, 8, false); + // name + $self.update_reference_position(end_position + 4); + $self.$name_converter(&$name_value); + // end + $self.add_end(end_position, &$span); + }; +} + +#[macro_export] +macro_rules! store_jsx_closing_fragment { + ($self:expr, span => $span:expr) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&44u32.to_ne_bytes(), &$span, 4, false); + // end + $self.add_end(end_position, &$span); + }; +} + +#[macro_export] +macro_rules! store_jsx_element { + ($self:expr, span => $span:expr, openingElement => [$openingElement_value:expr, $openingElement_converter:ident], children => [$children_value:expr, $children_converter:ident], closingElement => [$closingElement_value:expr, $closingElement_converter:ident]) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&45u32.to_ne_bytes(), &$span, 16, false); + // openingElement + $self.update_reference_position(end_position + 4); + $self.$openingElement_converter(&$openingElement_value); + // children + $self.convert_item_list(&$children_value, end_position + 8, |ast_converter, node| { + ast_converter.$children_converter(node); + true + }); + // closingElement + if let Some(value) = $closingElement_value.as_ref() { + $self.update_reference_position(end_position + 12); + $self.$closingElement_converter(value); + } + // end + $self.add_end(end_position, &$span); + }; +} + +#[macro_export] +macro_rules! store_jsx_fragment { + ($self:expr, span => $span:expr, openingFragment => [$openingFragment_value:expr, $openingFragment_converter:ident], children => [$children_value:expr, $children_converter:ident], closingFragment => [$closingFragment_value:expr, $closingFragment_converter:ident]) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&48u32.to_ne_bytes(), &$span, 16, false); + // openingFragment + $self.update_reference_position(end_position + 4); + $self.$openingFragment_converter(&$openingFragment_value); + // children + $self.convert_item_list(&$children_value, end_position + 8, |ast_converter, node| { + ast_converter.$children_converter(node); + true + }); + // closingFragment + $self.update_reference_position(end_position + 12); + $self.$closingFragment_converter(&$closingFragment_value); + // end + $self.add_end(end_position, &$span); + }; +} + +#[macro_export] +macro_rules! store_jsx_identifier { + ($self:expr, span => $span:expr, name => $name_value:expr) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&49u32.to_ne_bytes(), &$span, 8, false); + // name + $self.convert_string($name_value, end_position + 4); + // end + $self.add_end(end_position, &$span); + }; +} + +#[macro_export] +macro_rules! store_jsx_opening_fragment { + ($self:expr, span => $span:expr) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&53u32.to_ne_bytes(), &$span, 4, false); + // end + $self.add_end(end_position, &$span); + }; +} + +#[macro_export] +macro_rules! store_jsx_spread_child { + ($self:expr, span => $span:expr, expression => [$expression_value:expr, $expression_converter:ident]) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&55u32.to_ne_bytes(), &$span, 8, false); + // expression + $self.update_reference_position(end_position + 4); + $self.$expression_converter(&$expression_value); + // end + $self.add_end(end_position, &$span); + }; +} + +#[macro_export] +macro_rules! store_jsx_text { + ($self:expr, span => $span:expr, value => $value_value:expr, raw => $raw_value:expr) => { + let _: &mut AstConverter = $self; + let end_position = $self.add_type_and_start(&56u32.to_ne_bytes(), &$span, 12, false); + // value + $self.convert_string($value_value, end_position + 4); + // raw + $self.convert_string($raw_value, end_position + 8); + // end + $self.add_end(end_position, &$span); + }; +} + #[macro_export] macro_rules! store_labeled_statement { ($self:expr, span => $span:expr, label => [$label_value:expr, $label_converter:ident], body => [$body_value:expr, $body_converter:ident]) => { diff --git a/rust/parse_ast/src/convert_ast/converter/string_constants.rs b/rust/parse_ast/src/convert_ast/converter/string_constants.rs index 44bd9eed7a8..b5955be0eab 100644 --- a/rust/parse_ast/src/convert_ast/converter/string_constants.rs +++ b/rust/parse_ast/src/convert_ast/converter/string_constants.rs @@ -1,66 +1,66 @@ // This file is generated by scripts/generate-string-constants.js. // Do not edit this file directly. -pub(crate) const STRING_VAR: [u8; 4] = 0u32.to_ne_bytes(); // var -pub(crate) const STRING_LET: [u8; 4] = 1u32.to_ne_bytes(); // let -pub(crate) const STRING_CONST: [u8; 4] = 2u32.to_ne_bytes(); // const -pub(crate) const STRING_INIT: [u8; 4] = 3u32.to_ne_bytes(); // init -pub(crate) const STRING_GET: [u8; 4] = 4u32.to_ne_bytes(); // get -pub(crate) const STRING_SET: [u8; 4] = 5u32.to_ne_bytes(); // set -pub(crate) const STRING_CONSTRUCTOR: [u8; 4] = 6u32.to_ne_bytes(); // constructor -pub(crate) const STRING_METHOD: [u8; 4] = 7u32.to_ne_bytes(); // method -pub(crate) const STRING_MINUS: [u8; 4] = 8u32.to_ne_bytes(); // - -pub(crate) const STRING_PLUS: [u8; 4] = 9u32.to_ne_bytes(); // + -pub(crate) const STRING_BANG: [u8; 4] = 10u32.to_ne_bytes(); // ! -pub(crate) const STRING_TILDE: [u8; 4] = 11u32.to_ne_bytes(); // ~ -pub(crate) const STRING_TYPEOF: [u8; 4] = 12u32.to_ne_bytes(); // typeof -pub(crate) const STRING_VOID: [u8; 4] = 13u32.to_ne_bytes(); // void -pub(crate) const STRING_DELETE: [u8; 4] = 14u32.to_ne_bytes(); // delete -pub(crate) const STRING_PLUSPLUS: [u8; 4] = 15u32.to_ne_bytes(); // ++ -pub(crate) const STRING_MINUSMINUS: [u8; 4] = 16u32.to_ne_bytes(); // -- -pub(crate) const STRING_EQEQ: [u8; 4] = 17u32.to_ne_bytes(); // == -pub(crate) const STRING_NOTEQ: [u8; 4] = 18u32.to_ne_bytes(); // != -pub(crate) const STRING_EQEQEQ: [u8; 4] = 19u32.to_ne_bytes(); // === -pub(crate) const STRING_NOTEQEQ: [u8; 4] = 20u32.to_ne_bytes(); // !== -pub(crate) const STRING_LT: [u8; 4] = 21u32.to_ne_bytes(); // < -pub(crate) const STRING_LTEQ: [u8; 4] = 22u32.to_ne_bytes(); // <= -pub(crate) const STRING_GT: [u8; 4] = 23u32.to_ne_bytes(); // > -pub(crate) const STRING_GTEQ: [u8; 4] = 24u32.to_ne_bytes(); // >= -pub(crate) const STRING_LSHIFT: [u8; 4] = 25u32.to_ne_bytes(); // << -pub(crate) const STRING_RSHIFT: [u8; 4] = 26u32.to_ne_bytes(); // >> -pub(crate) const STRING_ZEROFILLRSHIFT: [u8; 4] = 27u32.to_ne_bytes(); // >>> -pub(crate) const STRING_ADD: [u8; 4] = 28u32.to_ne_bytes(); // + -pub(crate) const STRING_SUB: [u8; 4] = 29u32.to_ne_bytes(); // - -pub(crate) const STRING_MUL: [u8; 4] = 30u32.to_ne_bytes(); // * -pub(crate) const STRING_DIV: [u8; 4] = 31u32.to_ne_bytes(); // / -pub(crate) const STRING_MOD: [u8; 4] = 32u32.to_ne_bytes(); // % -pub(crate) const STRING_BITOR: [u8; 4] = 33u32.to_ne_bytes(); // | -pub(crate) const STRING_BITXOR: [u8; 4] = 34u32.to_ne_bytes(); // ^ -pub(crate) const STRING_BITAND: [u8; 4] = 35u32.to_ne_bytes(); // & -pub(crate) const STRING_LOGICALOR: [u8; 4] = 36u32.to_ne_bytes(); // || -pub(crate) const STRING_LOGICALAND: [u8; 4] = 37u32.to_ne_bytes(); // && -pub(crate) const STRING_IN: [u8; 4] = 38u32.to_ne_bytes(); // in -pub(crate) const STRING_INSTANCEOF: [u8; 4] = 39u32.to_ne_bytes(); // instanceof -pub(crate) const STRING_EXP: [u8; 4] = 40u32.to_ne_bytes(); // ** -pub(crate) const STRING_NULLISHCOALESCING: [u8; 4] = 41u32.to_ne_bytes(); // ?? -pub(crate) const STRING_ASSIGN: [u8; 4] = 42u32.to_ne_bytes(); // = -pub(crate) const STRING_ADDASSIGN: [u8; 4] = 43u32.to_ne_bytes(); // += -pub(crate) const STRING_SUBASSIGN: [u8; 4] = 44u32.to_ne_bytes(); // -= -pub(crate) const STRING_MULASSIGN: [u8; 4] = 45u32.to_ne_bytes(); // *= -pub(crate) const STRING_DIVASSIGN: [u8; 4] = 46u32.to_ne_bytes(); // /= -pub(crate) const STRING_MODASSIGN: [u8; 4] = 47u32.to_ne_bytes(); // %= -pub(crate) const STRING_LSHIFTASSIGN: [u8; 4] = 48u32.to_ne_bytes(); // <<= -pub(crate) const STRING_RSHIFTASSIGN: [u8; 4] = 49u32.to_ne_bytes(); // >>= -pub(crate) const STRING_ZEROFILLRSHIFTASSIGN: [u8; 4] = 50u32.to_ne_bytes(); // >>>= -pub(crate) const STRING_BITORASSIGN: [u8; 4] = 51u32.to_ne_bytes(); // |= -pub(crate) const STRING_BITXORASSIGN: [u8; 4] = 52u32.to_ne_bytes(); // ^= -pub(crate) const STRING_BITANDASSIGN: [u8; 4] = 53u32.to_ne_bytes(); // &= -pub(crate) const STRING_EXPASSIGN: [u8; 4] = 54u32.to_ne_bytes(); // **= -pub(crate) const STRING_ANDASSIGN: [u8; 4] = 55u32.to_ne_bytes(); // &&= -pub(crate) const STRING_ORASSIGN: [u8; 4] = 56u32.to_ne_bytes(); // ||= -pub(crate) const STRING_NULLISHASSIGN: [u8; 4] = 57u32.to_ne_bytes(); // ??= -pub(crate) const STRING_PURE: [u8; 4] = 58u32.to_ne_bytes(); // pure -pub(crate) const STRING_NOSIDEEFFECTS: [u8; 4] = 59u32.to_ne_bytes(); // noSideEffects -pub(crate) const STRING_SOURCEMAP: [u8; 4] = 60u32.to_ne_bytes(); // sourcemap -pub(crate) const STRING_USING: [u8; 4] = 61u32.to_ne_bytes(); // using -pub(crate) const STRING_AWAIT_USING: [u8; 4] = 62u32.to_ne_bytes(); // await using +pub const STRING_VAR: [u8; 4] = 0u32.to_ne_bytes(); // var +pub const STRING_LET: [u8; 4] = 1u32.to_ne_bytes(); // let +pub const STRING_CONST: [u8; 4] = 2u32.to_ne_bytes(); // const +pub const STRING_INIT: [u8; 4] = 3u32.to_ne_bytes(); // init +pub const STRING_GET: [u8; 4] = 4u32.to_ne_bytes(); // get +pub const STRING_SET: [u8; 4] = 5u32.to_ne_bytes(); // set +pub const STRING_CONSTRUCTOR: [u8; 4] = 6u32.to_ne_bytes(); // constructor +pub const STRING_METHOD: [u8; 4] = 7u32.to_ne_bytes(); // method +pub const STRING_MINUS: [u8; 4] = 8u32.to_ne_bytes(); // - +pub const STRING_PLUS: [u8; 4] = 9u32.to_ne_bytes(); // + +pub const STRING_BANG: [u8; 4] = 10u32.to_ne_bytes(); // ! +pub const STRING_TILDE: [u8; 4] = 11u32.to_ne_bytes(); // ~ +pub const STRING_TYPEOF: [u8; 4] = 12u32.to_ne_bytes(); // typeof +pub const STRING_VOID: [u8; 4] = 13u32.to_ne_bytes(); // void +pub const STRING_DELETE: [u8; 4] = 14u32.to_ne_bytes(); // delete +pub const STRING_PLUSPLUS: [u8; 4] = 15u32.to_ne_bytes(); // ++ +pub const STRING_MINUSMINUS: [u8; 4] = 16u32.to_ne_bytes(); // -- +pub const STRING_EQEQ: [u8; 4] = 17u32.to_ne_bytes(); // == +pub const STRING_NOTEQ: [u8; 4] = 18u32.to_ne_bytes(); // != +pub const STRING_EQEQEQ: [u8; 4] = 19u32.to_ne_bytes(); // === +pub const STRING_NOTEQEQ: [u8; 4] = 20u32.to_ne_bytes(); // !== +pub const STRING_LT: [u8; 4] = 21u32.to_ne_bytes(); // < +pub const STRING_LTEQ: [u8; 4] = 22u32.to_ne_bytes(); // <= +pub const STRING_GT: [u8; 4] = 23u32.to_ne_bytes(); // > +pub const STRING_GTEQ: [u8; 4] = 24u32.to_ne_bytes(); // >= +pub const STRING_LSHIFT: [u8; 4] = 25u32.to_ne_bytes(); // << +pub const STRING_RSHIFT: [u8; 4] = 26u32.to_ne_bytes(); // >> +pub const STRING_ZEROFILLRSHIFT: [u8; 4] = 27u32.to_ne_bytes(); // >>> +pub const STRING_ADD: [u8; 4] = 28u32.to_ne_bytes(); // + +pub const STRING_SUB: [u8; 4] = 29u32.to_ne_bytes(); // - +pub const STRING_MUL: [u8; 4] = 30u32.to_ne_bytes(); // * +pub const STRING_DIV: [u8; 4] = 31u32.to_ne_bytes(); // / +pub const STRING_MOD: [u8; 4] = 32u32.to_ne_bytes(); // % +pub const STRING_BITOR: [u8; 4] = 33u32.to_ne_bytes(); // | +pub const STRING_BITXOR: [u8; 4] = 34u32.to_ne_bytes(); // ^ +pub const STRING_BITAND: [u8; 4] = 35u32.to_ne_bytes(); // & +pub const STRING_LOGICALOR: [u8; 4] = 36u32.to_ne_bytes(); // || +pub const STRING_LOGICALAND: [u8; 4] = 37u32.to_ne_bytes(); // && +pub const STRING_IN: [u8; 4] = 38u32.to_ne_bytes(); // in +pub const STRING_INSTANCEOF: [u8; 4] = 39u32.to_ne_bytes(); // instanceof +pub const STRING_EXP: [u8; 4] = 40u32.to_ne_bytes(); // ** +pub const STRING_NULLISHCOALESCING: [u8; 4] = 41u32.to_ne_bytes(); // ?? +pub const STRING_ASSIGN: [u8; 4] = 42u32.to_ne_bytes(); // = +pub const STRING_ADDASSIGN: [u8; 4] = 43u32.to_ne_bytes(); // += +pub const STRING_SUBASSIGN: [u8; 4] = 44u32.to_ne_bytes(); // -= +pub const STRING_MULASSIGN: [u8; 4] = 45u32.to_ne_bytes(); // *= +pub const STRING_DIVASSIGN: [u8; 4] = 46u32.to_ne_bytes(); // /= +pub const STRING_MODASSIGN: [u8; 4] = 47u32.to_ne_bytes(); // %= +pub const STRING_LSHIFTASSIGN: [u8; 4] = 48u32.to_ne_bytes(); // <<= +pub const STRING_RSHIFTASSIGN: [u8; 4] = 49u32.to_ne_bytes(); // >>= +pub const STRING_ZEROFILLRSHIFTASSIGN: [u8; 4] = 50u32.to_ne_bytes(); // >>>= +pub const STRING_BITORASSIGN: [u8; 4] = 51u32.to_ne_bytes(); // |= +pub const STRING_BITXORASSIGN: [u8; 4] = 52u32.to_ne_bytes(); // ^= +pub const STRING_BITANDASSIGN: [u8; 4] = 53u32.to_ne_bytes(); // &= +pub const STRING_EXPASSIGN: [u8; 4] = 54u32.to_ne_bytes(); // **= +pub const STRING_ANDASSIGN: [u8; 4] = 55u32.to_ne_bytes(); // &&= +pub const STRING_ORASSIGN: [u8; 4] = 56u32.to_ne_bytes(); // ||= +pub const STRING_NULLISHASSIGN: [u8; 4] = 57u32.to_ne_bytes(); // ??= +pub const STRING_PURE: [u8; 4] = 58u32.to_ne_bytes(); // pure +pub const STRING_NOSIDEEFFECTS: [u8; 4] = 59u32.to_ne_bytes(); // noSideEffects +pub const STRING_SOURCEMAP: [u8; 4] = 60u32.to_ne_bytes(); // sourcemap +pub const STRING_USING: [u8; 4] = 61u32.to_ne_bytes(); // using +pub const STRING_AWAIT_USING: [u8; 4] = 62u32.to_ne_bytes(); // await using diff --git a/scripts/ast-types.js b/scripts/ast-types.js index af222ffeb56..2483f27b8f4 100644 --- a/scripts/ast-types.js +++ b/scripts/ast-types.js @@ -394,18 +394,15 @@ export const AST_NODES = { fields: [ ['name', 'Node'], ['value', 'OptionalNode'] - ], - useMacro: false + ] }, JSXClosingElement: { estreeType: 'any', - fields: [['name', 'Node']], - useMacro: false + fields: [['name', 'Node']] }, JSXClosingFragment: { estreeType: 'any', - fields: [], - useMacro: false + fields: [] }, JSXElement: { estreeType: 'any', @@ -413,8 +410,7 @@ export const AST_NODES = { ['openingElement', 'Node'], ['children', 'NodeList'], ['closingElement', 'OptionalNode'] - ], - useMacro: false + ] }, JSXEmptyExpression: { estreeType: 'any', @@ -431,13 +427,11 @@ export const AST_NODES = { ['openingFragment', 'Node'], ['children', 'NodeList'], ['closingFragment', 'Node'] - ], - useMacro: false + ] }, JSXIdentifier: { estreeType: 'any', - fields: [['name', 'String']], - useMacro: false + fields: [['name', 'String']] }, JSXMemberExpression: { estreeType: 'any', @@ -469,8 +463,7 @@ export const AST_NODES = { attributes: '[]', selfClosing: 'false' }, - estreeType: 'any', - useMacro: false + estreeType: 'any' }, JSXSpreadAttribute: { estreeType: 'any', @@ -479,16 +472,14 @@ export const AST_NODES = { }, JSXSpreadChild: { estreeType: 'any', - fields: [['expression', 'Node']], - useMacro: false + fields: [['expression', 'Node']] }, JSXText: { estreeType: 'any', fields: [ ['value', 'String'], ['raw', 'String'] - ], - useMacro: false + ] }, LabeledStatement: { fields: [ From dbb30328c58b6a8ff755ad8d0d4615737c9efb3f Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 2 Aug 2024 14:49:40 +0200 Subject: [PATCH 35/62] Initial jsx rendering logic for simple cases --- src/Module.ts | 3 +- src/ast/nodes/JSXAttribute.ts | 22 +++--- src/ast/nodes/JSXElement.ts | 4 +- src/ast/nodes/JSXExpressionContainer.ts | 4 +- src/ast/nodes/JSXFragment.ts | 7 +- src/ast/nodes/JSXOpeningElement.ts | 78 +++++++++++++++---- src/ast/nodes/JSXOpeningFragment.ts | 21 +++-- src/ast/nodes/JSXSpreadAttribute.ts | 4 +- src/ast/nodes/JSXSpreadChild.ts | 4 +- src/ast/nodes/JSXText.ts | 4 +- src/ast/nodes/shared/JSXClosingBase.ts | 4 +- src/ast/nodes/shared/JSXOpeningBase.ts | 42 +++++++++- src/rollup/types.d.ts | 27 ++++--- src/utils/options/normalizeInputOptions.ts | 40 ++++++---- src/utils/options/options.ts | 16 ++-- .../jsx/preserves-jsx-attributes/_config.js | 2 +- .../jsx/preserves-jsx-child/_config.js | 2 +- .../jsx/preserves-jsx-closing/_config.js | 2 +- .../preserves-jsx-empty-expression/_config.js | 2 +- .../jsx/preserves-jsx-expression/_config.js | 2 +- .../jsx/preserves-jsx-fragment/_config.js | 2 +- .../_config.js | 2 +- .../jsx/preserves-jsx-self-closing/_config.js | 2 +- .../preserves-jsx-spread-attribute/_config.js | 2 +- .../jsx/preserves-jsx-spread-child/_config.js | 2 +- .../samples/jsx/preserves-jsx-text/_config.js | 2 +- .../jsx/preserves-react-global/_config.js | 4 +- .../jsx/preserves-react-internal/_config.js | 2 +- .../samples/jsx/preserves-react/_config.js | 2 +- .../jsx/transpiles-jsx-attributes/_config.js | 2 +- .../jsx/transpiles-jsx-child/_config.js | 2 +- .../jsx/transpiles-jsx-closing/_config.js | 2 +- .../_config.js | 2 +- .../jsx/transpiles-jsx-expression/_config.js | 2 +- .../jsx/transpiles-jsx-fragment/_config.js | 2 +- .../_config.js | 2 +- .../transpiles-jsx-self-closing/_config.js | 2 +- .../_config.js | 2 +- .../transpiles-jsx-spread-child/_config.js | 2 +- .../jsx/transpiles-jsx-text/_config.js | 2 +- .../jsx/transpiles-react-global/_config.js | 2 +- .../jsx/transpiles-react-internal/_config.js | 2 +- .../jsx/transpiles-react-jsx/_expected.js | 62 ++++++++++++--- .../samples/jsx/transpiles-react-jsx/jsx.js | 46 +++++++++++ .../samples/jsx/transpiles-react-jsx/main.js | 55 ++++++++++++- .../jsx/transpiles-react-jsx/other1.js | 5 +- .../jsx/transpiles-react-jsx/other2.js | 5 +- .../samples/jsx/transpiles-react/_config.js | 2 +- .../samples/jsx/missing-jsx-export/_config.js | 2 +- 49 files changed, 377 insertions(+), 136 deletions(-) diff --git a/src/Module.ts b/src/Module.ts index 19c984959c2..25e6e7a33de 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -41,7 +41,6 @@ import type { ModuleOptions, NormalizedInputOptions, NormalizedJsxOptions, - NormalizedJsxTranspileOptions, PartialNull, PreserveEntrySignaturesOption, ResolvedId, @@ -1248,7 +1247,7 @@ export default class Module { } private getImportedJsxFactoryVariable(baseName: string, nodeStart: number): Variable { - const { importSource } = this.scope.context.options.jsx as NormalizedJsxTranspileOptions; + const { importSource } = this.scope.context.options.jsx as NormalizedJsxOptions; const { id } = this.resolvedIds[importSource!]; const module = this.graph.modulesById.get(id)!; const [variable] = module.getVariableForExportName(baseName); diff --git a/src/ast/nodes/JSXAttribute.ts b/src/ast/nodes/JSXAttribute.ts index 0f3134ac910..0324b0924f3 100644 --- a/src/ast/nodes/JSXAttribute.ts +++ b/src/ast/nodes/JSXAttribute.ts @@ -18,19 +18,23 @@ export default class JSXAttribute extends NodeBase { render(code: MagicString, options: RenderOptions): void { super.render(code, options); - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { + const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (mode !== 'preserve') { const { name, value } = this; const key = name instanceof JSXIdentifier ? name.name : `${name.namespace.name}:${name.name.name}`; - const safeKey = stringifyObjectKeyIfNeeded(key); - if (key !== safeKey) { - code.overwrite(name.start, name.end, safeKey, { contentOnly: true }); - } - if (value) { - code.overwrite(name.end, value.start, ': ', { contentOnly: true }); + if (mode === 'automatic' && key === 'key') { + code.remove(name.start, value?.start || name.end); } else { - code.appendLeft(name.end, ': true'); + const safeKey = stringifyObjectKeyIfNeeded(key); + if (key !== safeKey) { + code.overwrite(name.start, name.end, safeKey, { contentOnly: true }); + } + if (value) { + code.overwrite(name.end, value.start, ': ', { contentOnly: true }); + } else { + code.appendLeft(name.end, ': true'); + } } } } diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index ffb77d84b11..eb417269dcc 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -18,8 +18,8 @@ export default class JSXElement extends NodeBase { children!: (JSXText | JSXExpressionContainer | JSXElement | JSXFragment | JSXSpreadChild)[]; render(code: MagicString, options: RenderOptions): void { - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (preserve) { + const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (mode === 'preserve') { super.render(code, options); } else { this.openingElement.render(code, options); diff --git a/src/ast/nodes/JSXExpressionContainer.ts b/src/ast/nodes/JSXExpressionContainer.ts index 746de6ede97..d4b001629c2 100644 --- a/src/ast/nodes/JSXExpressionContainer.ts +++ b/src/ast/nodes/JSXExpressionContainer.ts @@ -11,8 +11,8 @@ export default class JSXExpressionContainer extends NodeBase { expression!: ExpressionNode | JSXEmptyExpression; render(code: MagicString, options: RenderOptions): void { - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { + const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (mode !== 'preserve') { code.remove(this.start, this.expression.start); code.remove(this.expression.end, this.end); } diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index 5c287c2670a..eaa2cbcc535 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -5,22 +5,21 @@ import type JSXClosingFragment from './JSXClosingFragment'; import type JSXElement from './JSXElement'; import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; -import type JSXFragment from './JSXFragment'; import type JSXOpeningFragment from './JSXOpeningFragment'; import type JSXSpreadChild from './JSXSpreadChild'; import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; import { NodeBase } from './shared/Node'; -export default class JsxElement extends NodeBase { +export default class JSXFragment extends NodeBase { type!: NodeType.tJSXElement; openingFragment!: JSXOpeningFragment; children!: (JSXText | JSXExpressionContainer | JSXSpreadChild | JSXElement | JSXFragment)[]; closingFragment!: JSXClosingFragment; render(code: MagicString, options: RenderOptions): void { - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (preserve) { + const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (mode === 'preserve') { super.render(code, options); } else { this.openingFragment.render(code, options); diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index bd5bc8b0e42..76f9320bd01 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -17,8 +17,8 @@ export default class JSXOpeningElement extends JSXOpeningBase { render(code: MagicString, options: RenderOptions): void { super.render(code, options); - const { factory, preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + if (jsx.mode !== 'preserve') { const { snippets: { getPropertyAccess }, useOriginalName @@ -31,38 +31,39 @@ export default class JSXOpeningElement extends JSXOpeningBase { selfClosing, start } = this; - const [, ...nestedName] = factory.split('.'); + const [, ...nestedName] = jsx.mode === 'classic' ? jsx.factory.split('.') : []; code.overwrite( start, nameStart, `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, { contentOnly: true } ); - if (attributes.some(attribute => attribute instanceof JSXSpreadAttribute)) { - if (attributes.length === 1) { + const [regularAttributes, hasSpread, keyAttribute] = analyzeAttributes(jsx.mode, attributes); + if (hasSpread) { + if (regularAttributes.length === 1) { code.appendLeft(nameEnd, ','); - code.overwrite(attributes[0].end, end, '', { contentOnly: true }); + code.overwrite(attributes.at(-1)!.end, end, '', { contentOnly: true }); } else { code.appendLeft(nameEnd, ', Object.assign('); let inObject = false; - if (!(attributes[0] instanceof JSXSpreadAttribute)) { + if (!(regularAttributes[0] instanceof JSXSpreadAttribute)) { code.appendLeft(nameEnd, '{'); inObject = true; } - for (let index = 1; index < attributes.length; index++) { - const attribute = attributes[index]; + for (let index = 1; index < regularAttributes.length; index++) { + const attribute = regularAttributes[index]; if (attribute instanceof JSXSpreadAttribute) { if (inObject) { code.prependRight(attribute.start, '}, '); inObject = false; } else { - code.appendLeft(attributes[index - 1].end, ','); + code.appendLeft(regularAttributes[index - 1].end, ','); } } else { if (inObject) { - code.appendLeft(attributes[index - 1].end, ','); + code.appendLeft(regularAttributes[index - 1].end, ','); } else { - code.appendLeft(attributes[index - 1].end, ', {'); + code.appendLeft(regularAttributes[index - 1].end, ', {'); inObject = true; } } @@ -72,22 +73,65 @@ export default class JSXOpeningElement extends JSXOpeningBase { } code.overwrite(attributes.at(-1)!.end, end, ')', { contentOnly: true }); } - } else if (attributes.length > 0) { + } else if (regularAttributes.length > 0) { code.appendLeft(nameEnd, ', {'); - for (let index = 0; index < attributes.length - 1; index++) { - code.appendLeft(attributes[index].end, ', '); + for (let index = 0; index < regularAttributes.length - 1; index++) { + code.appendLeft(regularAttributes[index].end, ', '); } code.overwrite(attributes.at(-1)!.end, end, ' }', { contentOnly: true }); + } else if (keyAttribute) { + code.remove(nameEnd, keyAttribute.start); + code.overwrite(keyAttribute.end, end, `, {}`, { + contentOnly: true + }); } else { - code.overwrite(nameEnd, end, `, null`, { + code.overwrite(nameEnd, end, `, ${jsx.mode === 'classic' ? 'null' : '{}'}`, { contentOnly: true }); } if (selfClosing) { - code.appendLeft(end, ')'); + if (keyAttribute) { + const { value } = keyAttribute; + // This will appear to the left of the moved code... + code.appendLeft(end, ', '); + if (value) { + // ...and this will appear to the right + code.appendLeft(value.end, ')'); + code.move(value.start, value.end, end); + } else { + code.appendLeft(end, 'true)'); + } + } else { + code.appendLeft(end, ')'); + } } } } } + +function analyzeAttributes( + mode: 'automatic' | 'classic', + attributes: (JSXAttribute | JSXSpreadAttribute)[] +): [ + regularAttributes: (JSXAttribute | JSXSpreadAttribute)[], + hasSpread: boolean, + keyAttribute: JSXAttribute | null +] { + const extractKey = mode === 'automatic'; + const regularAttributes: (JSXAttribute | JSXSpreadAttribute)[] = []; + let keyAttribute: JSXAttribute | null = null; + let hasSpread = false; + for (const attribute of attributes) { + if (attribute instanceof JSXSpreadAttribute) { + hasSpread = true; + regularAttributes.push(attribute); + } else if (extractKey && attribute.name.name === 'key') { + keyAttribute = attribute; + } else { + regularAttributes.push(attribute); + } + } + return [regularAttributes, hasSpread, keyAttribute]; +} diff --git a/src/ast/nodes/JSXOpeningFragment.ts b/src/ast/nodes/JSXOpeningFragment.ts index b2aa476fb93..41bf64ea516 100644 --- a/src/ast/nodes/JSXOpeningFragment.ts +++ b/src/ast/nodes/JSXOpeningFragment.ts @@ -21,13 +21,13 @@ export default class JSXOpeningFragment extends JSXOpeningBase { options?: InclusionOptions ): void { if (!this.included) { - const { fragmentFactory, importSource, preserve } = this.scope.context.options - .jsx as NormalizedJsxOptions; - if (fragmentFactory != null) { + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + const fragment = jsx.mode === 'automatic' ? 'Fragment' : jsx.fragment; + if (fragment != null) { this.fragmentVariable = this.getAndIncludeFactoryVariable( - fragmentFactory, - preserve, - importSource + fragment, + jsx.mode === 'preserve', + jsx.importSource ); } } @@ -40,11 +40,10 @@ export default class JSXOpeningFragment extends JSXOpeningBase { snippets: { getPropertyAccess }, useOriginalName } = options; - const { factory, fragmentFactory, preserve } = this.scope.context.options - .jsx as NormalizedJsxOptions; - if (!preserve) { - const [, ...nestedFactory] = factory.split('.'); - const [, ...nestedFragment] = fragmentFactory.split('.'); + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + if (jsx.mode !== 'preserve') { + const [, ...nestedFactory] = jsx.mode === 'classic' ? jsx.factory.split('.') : []; + const [, ...nestedFragment] = jsx.mode === 'classic' ? jsx.fragment.split('.') : []; code.overwrite( this.start, this.end, diff --git a/src/ast/nodes/JSXSpreadAttribute.ts b/src/ast/nodes/JSXSpreadAttribute.ts index 7827fde6400..96f846a6c6c 100644 --- a/src/ast/nodes/JSXSpreadAttribute.ts +++ b/src/ast/nodes/JSXSpreadAttribute.ts @@ -11,8 +11,8 @@ export default class JSXSpreadAttribute extends NodeBase { render(code: MagicString, options: RenderOptions): void { this.argument.render(code, options); - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { + const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (mode !== 'preserve') { code.overwrite(this.start, this.argument.start, '', { contentOnly: true }); code.overwrite(this.argument.end, this.end, '', { contentOnly: true }); } diff --git a/src/ast/nodes/JSXSpreadChild.ts b/src/ast/nodes/JSXSpreadChild.ts index d8594f4fa37..f831e582692 100644 --- a/src/ast/nodes/JSXSpreadChild.ts +++ b/src/ast/nodes/JSXSpreadChild.ts @@ -11,8 +11,8 @@ export default class JSXSpreadChild extends NodeBase { render(code: MagicString, options: RenderOptions): void { super.render(code, options); - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { + const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (mode !== 'preserve') { code.overwrite(this.start, this.expression.start, '...', { contentOnly: true }); code.overwrite(this.expression.end, this.end, '', { contentOnly: true }); } diff --git a/src/ast/nodes/JSXText.ts b/src/ast/nodes/JSXText.ts index fe4962bfbd8..59e905cda2f 100644 --- a/src/ast/nodes/JSXText.ts +++ b/src/ast/nodes/JSXText.ts @@ -9,8 +9,8 @@ export default class JSXText extends NodeBase { raw!: string; render(code: MagicString) { - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { + const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (mode !== 'preserve') { code.overwrite(this.start, this.end, JSON.stringify(this.value), { contentOnly: true }); diff --git a/src/ast/nodes/shared/JSXClosingBase.ts b/src/ast/nodes/shared/JSXClosingBase.ts index def0e84a429..abd1d247eca 100644 --- a/src/ast/nodes/shared/JSXClosingBase.ts +++ b/src/ast/nodes/shared/JSXClosingBase.ts @@ -4,8 +4,8 @@ import { NodeBase } from './Node'; export default class JSXClosingBase extends NodeBase { render(code: MagicString): void { - const { preserve } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (!preserve) { + const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (mode !== 'preserve') { code.overwrite(this.start, this.end, ')', { contentOnly: true }); } } diff --git a/src/ast/nodes/shared/JSXOpeningBase.ts b/src/ast/nodes/shared/JSXOpeningBase.ts index b15d2b3a95a..c2653621790 100644 --- a/src/ast/nodes/shared/JSXOpeningBase.ts +++ b/src/ast/nodes/shared/JSXOpeningBase.ts @@ -2,10 +2,15 @@ import type { NormalizedJsxOptions } from '../../../rollup/types'; import type { InclusionContext } from '../../ExecutionContext'; import LocalVariable from '../../variables/LocalVariable'; import type Variable from '../../variables/Variable'; +import type JSXAttribute from '../JSXAttribute'; +import type JSXElement from '../JSXElement'; +import type JSXFragment from '../JSXFragment'; +import JSXSpreadAttribute from '../JSXSpreadAttribute'; import type { InclusionOptions } from './Expression'; import { type IncludeChildren, NodeBase } from './Node'; export default class JSXOpeningBase extends NodeBase { + attributes!: (JSXAttribute | JSXSpreadAttribute)[]; protected factoryVariable: Variable | null = null; include( @@ -15,10 +20,26 @@ export default class JSXOpeningBase extends NodeBase { ): void { if (!this.deoptimized) this.applyDeoptimizations(); if (!this.included) { - const { factory, importSource, preserve } = this.scope.context.options - .jsx as NormalizedJsxOptions; - if (factory != null) { - this.factoryVariable = this.getAndIncludeFactoryVariable(factory, preserve, importSource); + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + switch (jsx.mode) { + case 'preserve': + case 'classic': { + if (jsx.factory) { + this.factoryVariable = this.getAndIncludeFactoryVariable( + jsx.factory, + jsx.mode === 'preserve', + jsx.importSource + ); + } + break; + } + case 'automatic': { + this.factoryVariable = this.getAndIncludeFactoryVariable( + this.getAutomaticJsxFactoryName(), + false, + jsx.importSource + ); + } } } super.include(context, includeChildrenRecursively, options); @@ -59,4 +80,17 @@ export default class JSXOpeningBase extends NodeBase { } return factoryVariable; } + + private getAutomaticJsxFactoryName() { + let hasSpread = false; + for (const attribute of this.attributes) { + if (attribute instanceof JSXSpreadAttribute) { + hasSpread = true; + } else if (hasSpread && attribute.name.name === 'key') { + return 'createElement'; + } + } + const parent = this.parent as JSXElement | JSXFragment; + return parent.children.length > 1 ? 'jsxs' : 'jsx'; + } } diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index a9ffa5ddd0c..a58feebcee6 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -525,20 +525,29 @@ export interface Plugin extends OutputPlugin, Partial { export type JsxPreset = 'react' | 'react-jsx' | 'preserve' | 'preserve-react'; -export type NormalizedJsxOptions = NormalizedJsxPreserveOptions | NormalizedJsxTranspileOptions; +export type NormalizedJsxOptions = + | NormalizedJsxPreserveOptions + | NormalizedJsxClassicOptions + | NormalizedJsxAutomaticOptions; -interface NormalizedJsxTranspileOptions { - factory: string; - fragmentFactory: string; +interface NormalizedJsxPreserveOptions { + factory: string | null; + fragment: string | null; importSource: string | null; - preserve: false; + mode: 'preserve'; } -interface NormalizedJsxPreserveOptions { - factory: string | null; - fragmentFactory: string | null; +interface NormalizedJsxClassicOptions { + factory: string; + fragment: string; importSource: string | null; - preserve: true; + mode: 'classic'; +} + +// TODO Lukas createElement must be imported from "react" at the moment -> jsxImportSource for jsx(s) and Fragment, importSource + factory for createElement +interface NormalizedJsxAutomaticOptions { + importSource: string; + mode: 'automatic'; } export type JsxOptions = Partial & { diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index c2aac4055a7..43b55dc54b2 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -119,26 +119,36 @@ const getInput = (config: InputOptions): NormalizedInputOptions['input'] => { const getJsx = (config: InputOptions): NormalizedInputOptions['jsx'] => { const configJsx = config.jsx; if (!configJsx) return false; - const configWithPreset = getOptionWithPreset( - configJsx, - jsxPresets, - 'jsx', - URL_JSX, - 'false, "preserve", ' - ); - return configWithPreset.preserve - ? { + const configWithPreset = getOptionWithPreset(configJsx, jsxPresets, 'jsx', URL_JSX, 'false, '); + switch (configWithPreset.mode) { + case 'automatic': { + return { + importSource: configWithPreset.importSource || 'react/jsx-runtime', + mode: 'automatic' + }; + } + case 'preserve': { + // TODO Lukas throw if there is an importSource but neither factory nor fragment + // TODO Lukas throw if there is no importSource but a fragment or factory that is not a valid identifier (with optional ".") + return { factory: configWithPreset.factory || null, - fragmentFactory: configWithPreset.fragmentFactory || null, + fragment: configWithPreset.fragment || null, importSource: configWithPreset.importSource || null, - preserve: true - } - : { + mode: 'preserve' + }; + } + // case 'classic': + default: { + // TODO Lukas throw if there is no importSource but a fragment or factory that is not a valid identifier + // TODO Lukas throw for unexpected mode + return { factory: configWithPreset.factory || 'React.createElement', - fragmentFactory: configWithPreset.fragmentFactory || 'React.Fragment', + fragment: configWithPreset.fragment || 'React.Fragment', importSource: configWithPreset.importSource || null, - preserve: false + mode: 'classic' }; + } + } }; const getMaxParallelFileOps = ( diff --git a/src/utils/options/options.ts b/src/utils/options/options.ts index 53ee5f36329..ff3a76ce174 100644 --- a/src/utils/options/options.ts +++ b/src/utils/options/options.ts @@ -142,27 +142,25 @@ export const jsxPresets: { } = { preserve: { factory: null, - fragmentFactory: null, + fragment: null, importSource: null, - preserve: true + mode: 'preserve' }, 'preserve-react': { factory: 'React.createElement', - fragmentFactory: 'React.Fragment', + fragment: 'React.Fragment', importSource: 'react', - preserve: true + mode: 'preserve' }, react: { factory: 'React.createElement', - fragmentFactory: 'React.Fragment', + fragment: 'React.Fragment', importSource: 'react', - preserve: false + mode: 'classic' }, 'react-jsx': { - factory: 'jsx', - fragmentFactory: 'Fragment', importSource: 'react/jsx-runtime', - preserve: false + mode: 'automatic' } }; diff --git a/test/form/samples/jsx/preserves-jsx-attributes/_config.js b/test/form/samples/jsx/preserves-jsx-attributes/_config.js index ffe19c7a1fa..0771bbaa44a 100644 --- a/test/form/samples/jsx/preserves-jsx-attributes/_config.js +++ b/test/form/samples/jsx/preserves-jsx-attributes/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js index ea00c851882..25cf84af18e 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-closing/_config.js b/test/form/samples/jsx/preserves-jsx-closing/_config.js index 9aa757698de..7de810bb5c3 100644 --- a/test/form/samples/jsx/preserves-jsx-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js index deba7dd3240..2aa4dbb212e 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-expression/_config.js b/test/form/samples/jsx/preserves-jsx-expression/_config.js index 60e522a1646..2063d648eda 100644 --- a/test/form/samples/jsx/preserves-jsx-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-fragment/_config.js b/test/form/samples/jsx/preserves-jsx-fragment/_config.js index deba7dd3240..2aa4dbb212e 100644 --- a/test/form/samples/jsx/preserves-jsx-fragment/_config.js +++ b/test/form/samples/jsx/preserves-jsx-fragment/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-member-expression/_config.js b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js index 23e0249f6ba..cffb8bd9fde 100644 --- a/test/form/samples/jsx/preserves-jsx-member-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX member expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-self-closing/_config.js b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js index ecb1f714963..c275d984aab 100644 --- a/test/form/samples/jsx/preserves-jsx-self-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves self-closing JSX elements', options: { jsx: 'preserve' diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js index b92dd30971f..6fee7232e10 100644 --- a/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/_config.js b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js index a9ea396f4d2..06718b59499 100644 --- a/test/form/samples/jsx/preserves-jsx-spread-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX spread children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-text/_config.js b/test/form/samples/jsx/preserves-jsx-text/_config.js index 07bcfdc8aea..256e8298a8b 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_config.js +++ b/test/form/samples/jsx/preserves-jsx-text/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves JSX text', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-react-global/_config.js b/test/form/samples/jsx/preserves-react-global/_config.js index e80ae4aeeec..ec0eaef8f71 100644 --- a/test/form/samples/jsx/preserves-react-global/_config.js +++ b/test/form/samples/jsx/preserves-react-global/_config.js @@ -1,11 +1,11 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves React variable when preserving JSX output', options: { jsx: { factory: 'React.createElement', fragmentFactory: 'React.Fragment', - preserve: true + mode: 'preserve' } } }); diff --git a/test/form/samples/jsx/preserves-react-internal/_config.js b/test/form/samples/jsx/preserves-react-internal/_config.js index bf4884466a2..3b06da7e7fd 100644 --- a/test/form/samples/jsx/preserves-react-internal/_config.js +++ b/test/form/samples/jsx/preserves-react-internal/_config.js @@ -1,7 +1,7 @@ const path = require('node:path'); module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves internal React variable when preserving JSX output', options: { jsx: { diff --git a/test/form/samples/jsx/preserves-react/_config.js b/test/form/samples/jsx/preserves-react/_config.js index 9f7101ac6f1..b535cda54e1 100644 --- a/test/form/samples/jsx/preserves-react/_config.js +++ b/test/form/samples/jsx/preserves-react/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'preserves React variable when preserving JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js index 2fd4e047609..4089b7bde6b 100644 --- a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-child/_config.js b/test/form/samples/jsx/transpiles-jsx-child/_config.js index c7ad9f42b8d..823f96b2e37 100644 --- a/test/form/samples/jsx/transpiles-jsx-child/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-closing/_config.js index 533cbcf1f3f..a229d2b5335 100644 --- a/test/form/samples/jsx/transpiles-jsx-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js index 3d8b1ae8455..879bd6f9a9c 100644 --- a/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-expression/_config.js index 3e4cce8489a..96e8d758b5c 100644 --- a/test/form/samples/jsx/transpiles-jsx-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-fragment/_config.js b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js index 3d8b1ae8455..879bd6f9a9c 100644 --- a/test/form/samples/jsx/transpiles-jsx-fragment/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js index b3c5bfcd03a..a97d293ec5c 100644 --- a/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX member expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js index aadd9cef2a9..4bc5cfb1104 100644 --- a/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles self-closing JSX elements', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js index 8301994aa10..bc3e773425d 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js index f744d02197b..298b30fd2ab 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX spread children', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-text/_config.js b/test/form/samples/jsx/transpiles-jsx-text/_config.js index 301d244b0ee..4e3be770a4e 100644 --- a/test/form/samples/jsx/transpiles-jsx-text/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-text/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX text', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-react-global/_config.js b/test/form/samples/jsx/transpiles-react-global/_config.js index ead07d867b4..da8f0585958 100644 --- a/test/form/samples/jsx/transpiles-react-global/_config.js +++ b/test/form/samples/jsx/transpiles-react-global/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX for react', options: { jsx: { diff --git a/test/form/samples/jsx/transpiles-react-internal/_config.js b/test/form/samples/jsx/transpiles-react-internal/_config.js index 0e8b9fe0132..ec4069a506d 100644 --- a/test/form/samples/jsx/transpiles-react-internal/_config.js +++ b/test/form/samples/jsx/transpiles-react-internal/_config.js @@ -1,6 +1,6 @@ const path = require('node:path'); module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX for react', options: { jsx: { diff --git a/test/form/samples/jsx/transpiles-react-jsx/_expected.js b/test/form/samples/jsx/transpiles-react-jsx/_expected.js index 88ebb128476..e4e4aeabb14 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_expected.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_expected.js @@ -1,12 +1,56 @@ -import { jsx as jsx$2 } from 'react/jsx-runtime'; +import { jsx, jsxs, Fragment, createElement } from 'react/jsx-runtime'; -const Foo$2 = 'wrong Foo 1'; -const jsx$1 = 'wrong jsx 1'; -console.log(Foo$2, jsx$1); +const Foo = () => {}; +const obj = { key: '2' }; -const Foo$1 = () => {}; -console.log(/*#__PURE__*/jsx$2(Foo$1, null)); +// jsx +console.log(/*#__PURE__*/jsx(Foo, {})); +console.log(/*#__PURE__*/jsx(Foo, { x: true })); +console.log(/*#__PURE__*/jsx(Foo, { x: "1" })); +console.log(/*#__PURE__*/jsx(Foo, { x: "1" })); +console.log(/*#__PURE__*/jsx(Foo, {}, true)); +console.log(/*#__PURE__*/jsx(Foo, {}, "1")); +console.log(/*#__PURE__*/jsx(Foo, {}, "1")); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj))); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { x: "1" }))); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj), "1")); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj))); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj), "1")); + +console.log(/*#__PURE__*/jsx(Foo, {})); +console.log(/*#__PURE__*/jsx(Foo, { x: "1" })); +console.log(/*#__PURE__*/jsx(Foo, {}, "1")); + +console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) })); +console.log(/*#__PURE__*/jsx(Foo, { x: "1", children: /*#__PURE__*/jsx(Foo, {}) })); +console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) }, "1")); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { children: /*#__PURE__*/jsx(Foo, {}) }))); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { x: "1", children: /*#__PURE__*/jsx(Foo, {}) }))); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), "1")); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: /*#__PURE__*/jsx(Foo, {}) }))); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), "1")); + +console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) })); + +console.log(/*#__PURE__*/jsx(_Fragment, {})); +console.log(/*#__PURE__*/jsx(_Fragment, { children: /*#__PURE__*/jsx(Foo, {}) })); + +// jsxs +console.log(/*#__PURE__*/jsxs(Foo, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); +console.log(/*#__PURE__*/jsxs(Foo, { x: "1", children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); +console.log(/*#__PURE__*/jsxs(Foo, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }, "1")); +console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }))); +console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { x: "1", children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }))); +console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), "1")); +console.log(/*#__PURE__*/jsxs(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }))); +console.log(/*#__PURE__*/jsxs(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), "1")); + +console.log(/*#__PURE__*/jsxs(_Fragment, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); + +// createElement +console.log(_createElement(Foo, Object.assign({}, obj, { key: "1" }))); +console.log(_createElement(Foo, Object.assign({}, obj, obj, { x: "1", key: "1", y: "1" }))); +console.log(_createElement(Foo, Object.assign({}, obj, { key: "1" }))); +console.log(_createElement(Foo, Object.assign({}, obj, { key: "1" }), + /*#__PURE__*/jsx(Foo, {}))); -const Foo = 'wrong Foo 2'; -const jsx = 'wrong jsx 2'; -console.log(Foo, jsx); diff --git a/test/form/samples/jsx/transpiles-react-jsx/jsx.js b/test/form/samples/jsx/transpiles-react-jsx/jsx.js index 4b5671bbbac..43ebc98b498 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/jsx.js +++ b/test/form/samples/jsx/transpiles-react-jsx/jsx.js @@ -1,2 +1,48 @@ const Foo = () => {}; +const obj = { key: '2' }; + +// jsx console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); + +console.log(); +console.log(); +console.log(); + +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); + +console.log({/* comment */}{/* comment */}); + +console.log(<>); +console.log(<>); + +// jsxs +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); + +console.log(<>); + +// createElement +console.log(); +console.log(); +console.log(); +console.log(); diff --git a/test/form/samples/jsx/transpiles-react-jsx/main.js b/test/form/samples/jsx/transpiles-react-jsx/main.js index dfccae85926..7da1f9e6297 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/main.js +++ b/test/form/samples/jsx/transpiles-react-jsx/main.js @@ -1,3 +1,52 @@ -import "./other1.js"; -import "./jsx.js"; -import "./other2.js"; +const Foo = () => {}; +const obj = { key: '2' }; + +// jsx +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); + +console.log(); +console.log(); +console.log(); + +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); + +console.log({/* comment */}{/* comment */}); + +console.log(<>); +console.log(<>); + +// jsxs +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); +console.log(); + +console.log(<>); + +// createElement +console.log(); +console.log(); +console.log(); +console.log(); diff --git a/test/form/samples/jsx/transpiles-react-jsx/other1.js b/test/form/samples/jsx/transpiles-react-jsx/other1.js index 8f9e29e5f2c..f99662c546c 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/other1.js +++ b/test/form/samples/jsx/transpiles-react-jsx/other1.js @@ -1,3 +1,6 @@ const Foo = 'wrong Foo 1'; +const obj = 'wrong obj 1'; const jsx = 'wrong jsx 1'; -console.log(Foo, jsx); +const jsxs = 'wrong jsxs 1'; +const createElement = 'wrong createElement 1'; +console.log(Foo, obj, jsx, jsxs, createElement); diff --git a/test/form/samples/jsx/transpiles-react-jsx/other2.js b/test/form/samples/jsx/transpiles-react-jsx/other2.js index fe345b1ba6b..c87092e813a 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/other2.js +++ b/test/form/samples/jsx/transpiles-react-jsx/other2.js @@ -1,3 +1,6 @@ const Foo = 'wrong Foo 2'; +const obj = 'wrong obj 2'; const jsx = 'wrong jsx 2'; -console.log(Foo, jsx); +const jsxs = 'wrong jsxs 2'; +const createElement = 'wrong createElement 2'; +console.log(Foo, obj, jsx, jsxs, createElement); diff --git a/test/form/samples/jsx/transpiles-react/_config.js b/test/form/samples/jsx/transpiles-react/_config.js index 7dbf6431642..830f5e41cd1 100644 --- a/test/form/samples/jsx/transpiles-react/_config.js +++ b/test/form/samples/jsx/transpiles-react/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, + // solo: true, description: 'transpiles JSX for react', options: { external: ['react'], diff --git a/test/function/samples/jsx/missing-jsx-export/_config.js b/test/function/samples/jsx/missing-jsx-export/_config.js index d62a8af710e..d806eb1e7cd 100644 --- a/test/function/samples/jsx/missing-jsx-export/_config.js +++ b/test/function/samples/jsx/missing-jsx-export/_config.js @@ -4,7 +4,7 @@ const ID_REACT = path.join(__dirname, 'react.js'); const ID_MAIN = path.join(__dirname, 'main.js'); module.exports = defineTest({ - solo: true, + // solo: true, description: 'throws when the JSX factory is not exported', options: { jsx: { From f90dbf3733c5150ed495116c3dc6973efb43aaf8 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 2 Aug 2024 15:12:20 +0200 Subject: [PATCH 36/62] Split classic and automatic mode --- src/ast/nodes/JSXOpeningElement.ts | 252 ++++++++++++------ .../jsx/preserves-jsx-attributes/_config.js | 2 +- .../jsx/preserves-jsx-child/_config.js | 2 +- .../jsx/preserves-jsx-closing/_config.js | 2 +- .../preserves-jsx-empty-expression/_config.js | 2 +- .../jsx/preserves-jsx-expression/_config.js | 2 +- .../jsx/preserves-jsx-fragment/_config.js | 2 +- .../_config.js | 2 +- .../jsx/preserves-jsx-self-closing/_config.js | 2 +- .../preserves-jsx-spread-attribute/_config.js | 2 +- .../jsx/preserves-jsx-spread-child/_config.js | 2 +- .../samples/jsx/preserves-jsx-text/_config.js | 2 +- .../jsx/preserves-react-global/_config.js | 2 +- .../jsx/preserves-react-internal/_config.js | 2 +- .../samples/jsx/preserves-react/_config.js | 2 +- .../jsx/transpiles-jsx-attributes/_config.js | 2 +- .../jsx/transpiles-jsx-child/_config.js | 2 +- .../jsx/transpiles-jsx-closing/_config.js | 2 +- .../_config.js | 2 +- .../jsx/transpiles-jsx-expression/_config.js | 2 +- .../jsx/transpiles-jsx-fragment/_config.js | 2 +- .../_config.js | 2 +- .../transpiles-jsx-self-closing/_config.js | 2 +- .../_config.js | 2 +- .../transpiles-jsx-spread-child/_config.js | 2 +- .../jsx/transpiles-jsx-text/_config.js | 2 +- .../jsx/transpiles-react-global/_config.js | 2 +- .../jsx/transpiles-react-internal/_config.js | 2 +- .../samples/jsx/transpiles-react/_config.js | 2 +- .../samples/jsx/missing-jsx-export/_config.js | 2 +- 30 files changed, 202 insertions(+), 108 deletions(-) diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index 76f9320bd01..c40d653c405 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -1,5 +1,9 @@ import type MagicString from 'magic-string'; -import type { NormalizedJsxOptions } from '../../rollup/types'; +import type { + NormalizedJsxAutomaticOptions, + NormalizedJsxClassicOptions, + NormalizedJsxOptions +} from '../../rollup/types'; import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXAttribute from './JSXAttribute'; import type JSXIdentifier from './JSXIdentifier'; @@ -18,94 +22,184 @@ export default class JSXOpeningElement extends JSXOpeningBase { render(code: MagicString, options: RenderOptions): void { super.render(code, options); const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - if (jsx.mode !== 'preserve') { - const { - snippets: { getPropertyAccess }, - useOriginalName - } = options; - const { - attributes, - end, - factoryVariable, - name: { start: nameStart, end: nameEnd }, - selfClosing, - start - } = this; - const [, ...nestedName] = jsx.mode === 'classic' ? jsx.factory.split('.') : []; - code.overwrite( - start, - nameStart, - `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, - { contentOnly: true } - ); - const [regularAttributes, hasSpread, keyAttribute] = analyzeAttributes(jsx.mode, attributes); - if (hasSpread) { - if (regularAttributes.length === 1) { - code.appendLeft(nameEnd, ','); - code.overwrite(attributes.at(-1)!.end, end, '', { contentOnly: true }); - } else { - code.appendLeft(nameEnd, ', Object.assign('); - let inObject = false; - if (!(regularAttributes[0] instanceof JSXSpreadAttribute)) { - code.appendLeft(nameEnd, '{'); - inObject = true; - } - for (let index = 1; index < regularAttributes.length; index++) { - const attribute = regularAttributes[index]; - if (attribute instanceof JSXSpreadAttribute) { - if (inObject) { - code.prependRight(attribute.start, '}, '); - inObject = false; - } else { - code.appendLeft(regularAttributes[index - 1].end, ','); - } + switch (jsx.mode) { + case 'classic': { + this.renderClassicMode(code, options, jsx); + break; + } + case 'automatic': { + this.renderAutomaticMode(code, options, jsx); + break; + } + } + } + + private renderClassicMode( + code: MagicString, + options: RenderOptions, + { factory }: NormalizedJsxClassicOptions + ) { + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + const { + attributes, + end, + factoryVariable, + name: { start: nameStart, end: nameEnd }, + selfClosing, + start + } = this; + const [, ...nestedName] = factory.split('.'); + code.overwrite( + start, + nameStart, + `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, + { contentOnly: true } + ); + if (attributes.some(attribute => attribute instanceof JSXSpreadAttribute)) { + if (attributes.length === 1) { + code.appendLeft(nameEnd, ','); + code.overwrite(attributes[0].end, end, '', { contentOnly: true }); + } else { + code.appendLeft(nameEnd, ', Object.assign('); + let inObject = false; + if (!(attributes[0] instanceof JSXSpreadAttribute)) { + code.appendLeft(nameEnd, '{'); + inObject = true; + } + for (let index = 1; index < attributes.length; index++) { + const attribute = attributes[index]; + if (attribute instanceof JSXSpreadAttribute) { + if (inObject) { + code.prependRight(attribute.start, '}, '); + inObject = false; } else { - if (inObject) { - code.appendLeft(regularAttributes[index - 1].end, ','); - } else { - code.appendLeft(regularAttributes[index - 1].end, ', {'); - inObject = true; - } + code.appendLeft(attributes[index - 1].end, ','); + } + } else { + if (inObject) { + code.appendLeft(attributes[index - 1].end, ','); + } else { + code.appendLeft(attributes[index - 1].end, ', {'); + inObject = true; } } - if (inObject) { - code.appendLeft(attributes.at(-1)!.end, ' }'); - } - code.overwrite(attributes.at(-1)!.end, end, ')', { contentOnly: true }); } - } else if (regularAttributes.length > 0) { - code.appendLeft(nameEnd, ', {'); - for (let index = 0; index < regularAttributes.length - 1; index++) { - code.appendLeft(regularAttributes[index].end, ', '); + if (inObject) { + code.appendLeft(attributes.at(-1)!.end, ' }'); } - code.overwrite(attributes.at(-1)!.end, end, ' }', { - contentOnly: true - }); - } else if (keyAttribute) { - code.remove(nameEnd, keyAttribute.start); - code.overwrite(keyAttribute.end, end, `, {}`, { - contentOnly: true - }); - } else { - code.overwrite(nameEnd, end, `, ${jsx.mode === 'classic' ? 'null' : '{}'}`, { - contentOnly: true - }); + code.overwrite(attributes.at(-1)!.end, end, ')', { contentOnly: true }); + } + } else if (attributes.length > 0) { + code.appendLeft(nameEnd, ', {'); + for (let index = 0; index < attributes.length - 1; index++) { + code.appendLeft(attributes[index].end, ', '); } - if (selfClosing) { - if (keyAttribute) { - const { value } = keyAttribute; - // This will appear to the left of the moved code... - code.appendLeft(end, ', '); - if (value) { - // ...and this will appear to the right - code.appendLeft(value.end, ')'); - code.move(value.start, value.end, end); + code.overwrite(attributes.at(-1)!.end, end, ' }', { + contentOnly: true + }); + } else { + code.overwrite(nameEnd, end, ', null', { + contentOnly: true + }); + } + if (selfClosing) { + code.appendLeft(end, ')'); + } + } + + private renderAutomaticMode( + code: MagicString, + options: RenderOptions, + jsx: NormalizedJsxAutomaticOptions + ) { + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + const { + attributes, + end, + factoryVariable, + name: { start: nameStart, end: nameEnd }, + selfClosing, + start + } = this; + code.overwrite( + start, + nameStart, + `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(`, + { contentOnly: true } + ); + const [regularAttributes, hasSpread, keyAttribute] = analyzeAttributes(jsx.mode, attributes); + if (hasSpread) { + if (regularAttributes.length === 1) { + code.appendLeft(nameEnd, ','); + code.overwrite(attributes.at(-1)!.end, end, '', { contentOnly: true }); + } else { + code.appendLeft(nameEnd, ', Object.assign('); + let inObject = false; + if (!(regularAttributes[0] instanceof JSXSpreadAttribute)) { + code.appendLeft(nameEnd, '{'); + inObject = true; + } + for (let index = 1; index < regularAttributes.length; index++) { + const attribute = regularAttributes[index]; + if (attribute instanceof JSXSpreadAttribute) { + if (inObject) { + code.prependRight(attribute.start, '}, '); + inObject = false; + } else { + code.appendLeft(regularAttributes[index - 1].end, ','); + } } else { - code.appendLeft(end, 'true)'); + if (inObject) { + code.appendLeft(regularAttributes[index - 1].end, ','); + } else { + code.appendLeft(regularAttributes[index - 1].end, ', {'); + inObject = true; + } } + } + if (inObject) { + code.appendLeft(attributes.at(-1)!.end, ' }'); + } + code.overwrite(attributes.at(-1)!.end, end, ')', { contentOnly: true }); + } + } else if (regularAttributes.length > 0) { + code.appendLeft(nameEnd, ', {'); + for (let index = 0; index < regularAttributes.length - 1; index++) { + code.appendLeft(regularAttributes[index].end, ', '); + } + code.overwrite(attributes.at(-1)!.end, end, ' }', { + contentOnly: true + }); + } else if (keyAttribute) { + code.remove(nameEnd, keyAttribute.start); + code.overwrite(keyAttribute.end, end, `, {}`, { + contentOnly: true + }); + } else { + code.overwrite(nameEnd, end, `, {}`, { + contentOnly: true + }); + } + if (selfClosing) { + if (keyAttribute) { + const { value } = keyAttribute; + // This will appear to the left of the moved code... + code.appendLeft(end, ', '); + if (value) { + // ...and this will appear to the right + code.appendLeft(value.end, ')'); + code.move(value.start, value.end, end); } else { - code.appendLeft(end, ')'); + code.appendLeft(end, 'true)'); } + } else { + code.appendLeft(end, ')'); } } } diff --git a/test/form/samples/jsx/preserves-jsx-attributes/_config.js b/test/form/samples/jsx/preserves-jsx-attributes/_config.js index 0771bbaa44a..754b6da75d8 100644 --- a/test/form/samples/jsx/preserves-jsx-attributes/_config.js +++ b/test/form/samples/jsx/preserves-jsx-attributes/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js index 25cf84af18e..2b0c707ba7a 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-closing/_config.js b/test/form/samples/jsx/preserves-jsx-closing/_config.js index 7de810bb5c3..9cb85863186 100644 --- a/test/form/samples/jsx/preserves-jsx-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js index 2aa4dbb212e..207155a631b 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-expression/_config.js b/test/form/samples/jsx/preserves-jsx-expression/_config.js index 2063d648eda..a7a6c15cc6e 100644 --- a/test/form/samples/jsx/preserves-jsx-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-fragment/_config.js b/test/form/samples/jsx/preserves-jsx-fragment/_config.js index 2aa4dbb212e..207155a631b 100644 --- a/test/form/samples/jsx/preserves-jsx-fragment/_config.js +++ b/test/form/samples/jsx/preserves-jsx-fragment/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-member-expression/_config.js b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js index cffb8bd9fde..628a4fd9b42 100644 --- a/test/form/samples/jsx/preserves-jsx-member-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX member expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-self-closing/_config.js b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js index c275d984aab..dbf7d29c1c2 100644 --- a/test/form/samples/jsx/preserves-jsx-self-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves self-closing JSX elements', options: { jsx: 'preserve' diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js index 6fee7232e10..7ee095abe33 100644 --- a/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/_config.js b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js index 06718b59499..f9f75d73aaf 100644 --- a/test/form/samples/jsx/preserves-jsx-spread-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX spread children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-text/_config.js b/test/form/samples/jsx/preserves-jsx-text/_config.js index 256e8298a8b..b653e85ee71 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_config.js +++ b/test/form/samples/jsx/preserves-jsx-text/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves JSX text', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-react-global/_config.js b/test/form/samples/jsx/preserves-react-global/_config.js index ec0eaef8f71..46ca52230f7 100644 --- a/test/form/samples/jsx/preserves-react-global/_config.js +++ b/test/form/samples/jsx/preserves-react-global/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves React variable when preserving JSX output', options: { jsx: { diff --git a/test/form/samples/jsx/preserves-react-internal/_config.js b/test/form/samples/jsx/preserves-react-internal/_config.js index 3b06da7e7fd..e23f4cc4666 100644 --- a/test/form/samples/jsx/preserves-react-internal/_config.js +++ b/test/form/samples/jsx/preserves-react-internal/_config.js @@ -1,7 +1,7 @@ const path = require('node:path'); module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves internal React variable when preserving JSX output', options: { jsx: { diff --git a/test/form/samples/jsx/preserves-react/_config.js b/test/form/samples/jsx/preserves-react/_config.js index b535cda54e1..863409c0ed8 100644 --- a/test/form/samples/jsx/preserves-react/_config.js +++ b/test/form/samples/jsx/preserves-react/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'preserves React variable when preserving JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js index 4089b7bde6b..28d600c8510 100644 --- a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-child/_config.js b/test/form/samples/jsx/transpiles-jsx-child/_config.js index 823f96b2e37..89b9be282e0 100644 --- a/test/form/samples/jsx/transpiles-jsx-child/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-closing/_config.js index a229d2b5335..a54263d2370 100644 --- a/test/form/samples/jsx/transpiles-jsx-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js index 879bd6f9a9c..3f1ad493810 100644 --- a/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-expression/_config.js index 96e8d758b5c..f0187c22730 100644 --- a/test/form/samples/jsx/transpiles-jsx-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-fragment/_config.js b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js index 879bd6f9a9c..3f1ad493810 100644 --- a/test/form/samples/jsx/transpiles-jsx-fragment/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js index a97d293ec5c..9bf52de2829 100644 --- a/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX member expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js index 4bc5cfb1104..dbf66b0a6cd 100644 --- a/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles self-closing JSX elements', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js index bc3e773425d..56309e9fab1 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js index 298b30fd2ab..104ad1c6d7c 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX spread children', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-text/_config.js b/test/form/samples/jsx/transpiles-jsx-text/_config.js index 4e3be770a4e..ef037c71abb 100644 --- a/test/form/samples/jsx/transpiles-jsx-text/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-text/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX text', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-react-global/_config.js b/test/form/samples/jsx/transpiles-react-global/_config.js index da8f0585958..dfa379a12e9 100644 --- a/test/form/samples/jsx/transpiles-react-global/_config.js +++ b/test/form/samples/jsx/transpiles-react-global/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX for react', options: { jsx: { diff --git a/test/form/samples/jsx/transpiles-react-internal/_config.js b/test/form/samples/jsx/transpiles-react-internal/_config.js index ec4069a506d..41a45f0932d 100644 --- a/test/form/samples/jsx/transpiles-react-internal/_config.js +++ b/test/form/samples/jsx/transpiles-react-internal/_config.js @@ -1,6 +1,6 @@ const path = require('node:path'); module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX for react', options: { jsx: { diff --git a/test/form/samples/jsx/transpiles-react/_config.js b/test/form/samples/jsx/transpiles-react/_config.js index 830f5e41cd1..0cd5a0ab494 100644 --- a/test/form/samples/jsx/transpiles-react/_config.js +++ b/test/form/samples/jsx/transpiles-react/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'transpiles JSX for react', options: { external: ['react'], diff --git a/test/function/samples/jsx/missing-jsx-export/_config.js b/test/function/samples/jsx/missing-jsx-export/_config.js index d806eb1e7cd..2aaf1a60842 100644 --- a/test/function/samples/jsx/missing-jsx-export/_config.js +++ b/test/function/samples/jsx/missing-jsx-export/_config.js @@ -4,7 +4,7 @@ const ID_REACT = path.join(__dirname, 'react.js'); const ID_MAIN = path.join(__dirname, 'main.js'); module.exports = defineTest({ - // solo: true, + solo: true, //x, description: 'throws when the JSX factory is not exported', options: { jsx: { From 15467f057e61e0fc7414d0eba5a11eb3495fbfe6 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 2 Aug 2024 16:41:40 +0200 Subject: [PATCH 37/62] Handle jsx without children --- src/ast/nodes/JSXAttribute.ts | 4 +- src/ast/nodes/JSXOpeningElement.ts | 212 ++++++++++++++++------------- 2 files changed, 122 insertions(+), 94 deletions(-) diff --git a/src/ast/nodes/JSXAttribute.ts b/src/ast/nodes/JSXAttribute.ts index 0324b0924f3..c726e3b6a3e 100644 --- a/src/ast/nodes/JSXAttribute.ts +++ b/src/ast/nodes/JSXAttribute.ts @@ -23,9 +23,7 @@ export default class JSXAttribute extends NodeBase { const { name, value } = this; const key = name instanceof JSXIdentifier ? name.name : `${name.namespace.name}:${name.name.name}`; - if (mode === 'automatic' && key === 'key') { - code.remove(name.start, value?.start || name.end); - } else { + if (!(mode === 'automatic' && key === 'key')) { const safeKey = stringifyObjectKeyIfNeeded(key); if (key !== safeKey) { code.overwrite(name.start, name.end, safeKey, { contentOnly: true }); diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index c40d653c405..ea6252eca20 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -1,9 +1,5 @@ import type MagicString from 'magic-string'; -import type { - NormalizedJsxAutomaticOptions, - NormalizedJsxClassicOptions, - NormalizedJsxOptions -} from '../../rollup/types'; +import type { NormalizedJsxClassicOptions, NormalizedJsxOptions } from '../../rollup/types'; import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXAttribute from './JSXAttribute'; import type JSXIdentifier from './JSXIdentifier'; @@ -28,7 +24,7 @@ export default class JSXOpeningElement extends JSXOpeningBase { break; } case 'automatic': { - this.renderAutomaticMode(code, options, jsx); + this.renderAutomaticMode(code, options); break; } } @@ -110,11 +106,7 @@ export default class JSXOpeningElement extends JSXOpeningBase { } } - private renderAutomaticMode( - code: MagicString, - options: RenderOptions, - jsx: NormalizedJsxAutomaticOptions - ) { + private renderAutomaticMode(code: MagicString, options: RenderOptions) { const { snippets: { getPropertyAccess }, useOriginalName @@ -133,99 +125,137 @@ export default class JSXOpeningElement extends JSXOpeningBase { `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(`, { contentOnly: true } ); - const [regularAttributes, hasSpread, keyAttribute] = analyzeAttributes(jsx.mode, attributes); - if (hasSpread) { - if (regularAttributes.length === 1) { - code.appendLeft(nameEnd, ','); - code.overwrite(attributes.at(-1)!.end, end, '', { contentOnly: true }); - } else { - code.appendLeft(nameEnd, ', Object.assign('); - let inObject = false; - if (!(regularAttributes[0] instanceof JSXSpreadAttribute)) { - code.appendLeft(nameEnd, '{'); - inObject = true; - } - for (let index = 1; index < regularAttributes.length; index++) { - const attribute = regularAttributes[index]; - if (attribute instanceof JSXSpreadAttribute) { - if (inObject) { - code.prependRight(attribute.start, '}, '); - inObject = false; - } else { - code.appendLeft(regularAttributes[index - 1].end, ','); - } - } else { - if (inObject) { - code.appendLeft(regularAttributes[index - 1].end, ','); - } else { - code.appendLeft(regularAttributes[index - 1].end, ', {'); - inObject = true; - } + let keyAttribute: JSXAttribute | null = null; + let hasSpread = false; + let inObject = true; + let previousEnd = nameEnd; + let hasAttributes = false; + for (const attribute of attributes) { + if (attribute instanceof JSXSpreadAttribute) { + if (inObject) { + if (hasAttributes) { + code.appendLeft(previousEnd, ' '); } + code.appendLeft(previousEnd, '},'); + inObject = false; + } else if (hasAttributes) { + code.appendLeft(previousEnd, ','); } - if (inObject) { - code.appendLeft(attributes.at(-1)!.end, ' }'); + previousEnd = attribute.end; + hasAttributes = true; + hasSpread = true; + } else if (attribute.name.name === 'key') { + keyAttribute = attribute; + code.remove(previousEnd, attribute.value?.start || attribute.end); + } else { + if (hasAttributes) { + code.appendLeft(previousEnd, ','); } - code.overwrite(attributes.at(-1)!.end, end, ')', { contentOnly: true }); + if (!inObject) { + code.appendLeft(previousEnd, ' {'); + inObject = true; + } + previousEnd = attribute.end; + hasAttributes = true; } - } else if (regularAttributes.length > 0) { - code.appendLeft(nameEnd, ', {'); - for (let index = 0; index < regularAttributes.length - 1; index++) { - code.appendLeft(regularAttributes[index].end, ', '); + } + code.prependLeft(nameEnd, hasSpread ? ', Object.assign({' : ', {'); + if (inObject) { + if (hasAttributes) { + code.appendLeft(previousEnd, ' '); + } + code.update(attributes.at(-1)?.end || previousEnd, end, '}'); + if (hasSpread) { + code.appendLeft(end, ')'); } - code.overwrite(attributes.at(-1)!.end, end, ' }', { - contentOnly: true - }); - } else if (keyAttribute) { - code.remove(nameEnd, keyAttribute.start); - code.overwrite(keyAttribute.end, end, `, {}`, { - contentOnly: true - }); } else { - code.overwrite(nameEnd, end, `, {}`, { - contentOnly: true - }); + code.update(previousEnd, end, ')'); } - if (selfClosing) { - if (keyAttribute) { - const { value } = keyAttribute; - // This will appear to the left of the moved code... - code.appendLeft(end, ', '); - if (value) { + // TODO Lukas this should be relative to the parent if there are children + if (keyAttribute) { + const { value } = keyAttribute; + // This will appear to the left of the moved code... + code.appendLeft(end, ', '); + if (value) { + if (selfClosing) { // ...and this will appear to the right code.appendLeft(value.end, ')'); - code.move(value.start, value.end, end); - } else { - code.appendLeft(end, 'true)'); } + code.move(value.start, value.end, end); } else { - code.appendLeft(end, ')'); + code.appendLeft(end, 'true)'); } + } else if (selfClosing) { + code.appendLeft(end, ')'); } - } -} -function analyzeAttributes( - mode: 'automatic' | 'classic', - attributes: (JSXAttribute | JSXSpreadAttribute)[] -): [ - regularAttributes: (JSXAttribute | JSXSpreadAttribute)[], - hasSpread: boolean, - keyAttribute: JSXAttribute | null -] { - const extractKey = mode === 'automatic'; - const regularAttributes: (JSXAttribute | JSXSpreadAttribute)[] = []; - let keyAttribute: JSXAttribute | null = null; - let hasSpread = false; - for (const attribute of attributes) { - if (attribute instanceof JSXSpreadAttribute) { - hasSpread = true; - regularAttributes.push(attribute); - } else if (extractKey && attribute.name.name === 'key') { - keyAttribute = attribute; - } else { - regularAttributes.push(attribute); - } + // if (hasSpread) { + // if (regularAttributes.length === 1) { + // code.appendLeft(nameEnd, ','); + // code.overwrite(attributes.at(-1)!.end, end, '', { contentOnly: true }); + // } else { + // code.appendLeft(nameEnd, ', Object.assign('); + // let inObject = false; + // if (!(regularAttributes[0] instanceof JSXSpreadAttribute)) { + // code.appendLeft(nameEnd, '{'); + // inObject = true; + // } + // for (let index = 1; index < regularAttributes.length; index++) { + // const attribute = regularAttributes[index]; + // if (attribute instanceof JSXSpreadAttribute) { + // if (inObject) { + // code.prependRight(attribute.start, '}, '); + // inObject = false; + // } else { + // code.appendLeft(regularAttributes[index - 1].end, ','); + // } + // } else { + // if (inObject) { + // code.appendLeft(regularAttributes[index - 1].end, ','); + // } else { + // code.appendLeft(regularAttributes[index - 1].end, ', {'); + // inObject = true; + // } + // } + // } + // if (inObject) { + // code.appendLeft(attributes.at(-1)!.end, ' }'); + // } + // code.overwrite(attributes.at(-1)!.end, end, ')', { contentOnly: true }); + // } + // } else if (regularAttributes.length > 0) { + // code.appendLeft(nameEnd, ', {'); + // for (let index = 0; index < regularAttributes.length - 1; index++) { + // code.appendLeft(regularAttributes[index].end, ', '); + // } + // code.overwrite(attributes.at(-1)!.end, end, ' }', { + // contentOnly: true + // }); + // } else if (keyAttribute) { + // code.remove(nameEnd, keyAttribute.start); + // code.overwrite(keyAttribute.end, end, `, {}`, { + // contentOnly: true + // }); + // } else { + // code.overwrite(nameEnd, end, `, {}`, { + // contentOnly: true + // }); + // } + // if (selfClosing) { + // if (keyAttribute) { + // const { value } = keyAttribute; + // // This will appear to the left of the moved code... + // code.appendLeft(end, ', '); + // if (value) { + // // ...and this will appear to the right + // code.appendLeft(value.end, ')'); + // code.move(value.start, value.end, end); + // } else { + // code.appendLeft(end, 'true)'); + // } + // } else { + // code.appendLeft(end, ')'); + // } + // } } - return [regularAttributes, hasSpread, keyAttribute]; } From 6c8dd158fdf0577bff003f0ecd08f4e1d60dcce5 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 2 Aug 2024 21:44:25 +0200 Subject: [PATCH 38/62] Handle jsx with children --- src/ast/nodes/JSXElement.ts | 7 +- src/ast/nodes/JSXOpeningElement.ts | 144 +++++++----------- src/ast/nodes/shared/JSXOpeningBase.ts | 3 +- src/utils/jsx.ts | 20 +++ .../jsx/preserves-jsx-attributes/_config.js | 2 +- .../jsx/preserves-jsx-child/_config.js | 2 +- .../jsx/preserves-jsx-closing/_config.js | 2 +- .../preserves-jsx-empty-expression/_config.js | 2 +- .../jsx/preserves-jsx-expression/_config.js | 2 +- .../jsx/preserves-jsx-fragment/_config.js | 2 +- .../_config.js | 2 +- .../jsx/preserves-jsx-self-closing/_config.js | 2 +- .../preserves-jsx-spread-attribute/_config.js | 2 +- .../jsx/preserves-jsx-spread-child/_config.js | 2 +- .../samples/jsx/preserves-jsx-text/_config.js | 2 +- .../jsx/preserves-react-global/_config.js | 2 +- .../jsx/preserves-react-internal/_config.js | 2 +- .../samples/jsx/preserves-react/_config.js | 2 +- .../jsx/transpiles-jsx-attributes/_config.js | 2 +- .../jsx/transpiles-jsx-child/_config.js | 2 +- .../jsx/transpiles-jsx-closing/_config.js | 2 +- .../_config.js | 2 +- .../jsx/transpiles-jsx-expression/_config.js | 2 +- .../jsx/transpiles-jsx-fragment/_config.js | 2 +- .../_config.js | 2 +- .../transpiles-jsx-self-closing/_config.js | 2 +- .../_config.js | 2 +- .../transpiles-jsx-spread-child/_config.js | 2 +- .../jsx/transpiles-jsx-text/_config.js | 2 +- .../jsx/transpiles-react-global/_config.js | 2 +- .../jsx/transpiles-react-internal/_config.js | 2 +- .../jsx/transpiles-react-jsx/_expected.js | 17 ++- .../samples/jsx/transpiles-react-jsx/main.js | 11 ++ .../samples/jsx/transpiles-react/_config.js | 2 +- .../samples/jsx/missing-jsx-export/_config.js | 2 +- 35 files changed, 137 insertions(+), 123 deletions(-) create mode 100644 src/utils/jsx.ts diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index eb417269dcc..c06de3ece64 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -23,6 +23,7 @@ export default class JSXElement extends NodeBase { super.render(code, options); } else { this.openingElement.render(code, options); + let prependComma = mode === 'classic'; for (const child of this.children) { if ( child instanceof JSXExpressionContainer && @@ -31,7 +32,11 @@ export default class JSXElement extends NodeBase { code.remove(child.start, child.end); } else { child.render(code, options); - code.appendRight(child.start, `, `); + if (prependComma) { + code.appendLeft(child.start, `, `); + } else { + prependComma = true; + } } } this.closingElement?.render(code); diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index ea6252eca20..6bfd6b28eff 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -1,7 +1,10 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxClassicOptions, NormalizedJsxOptions } from '../../rollup/types'; +import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXAttribute from './JSXAttribute'; +import JSXElement from './JSXElement'; +import type JSXFragment from './JSXFragment'; import type JSXIdentifier from './JSXIdentifier'; import type JSXMemberExpression from './JSXMemberExpression'; import type JSXNamespacedName from './JSXNamespacedName'; @@ -160,102 +163,65 @@ export default class JSXOpeningElement extends JSXOpeningBase { } } code.prependLeft(nameEnd, hasSpread ? ', Object.assign({' : ', {'); - if (inObject) { + const closeObjectAssign = hasSpread ? ')' : ''; + const parent = this.parent as JSXElement | JSXFragment; + const renderedChildren = getRenderedJsxChildren(parent.children); + if (renderedChildren > 0) { if (hasAttributes) { - code.appendLeft(previousEnd, ' '); + code.appendLeft(previousEnd, ','); } - code.update(attributes.at(-1)?.end || previousEnd, end, '}'); - if (hasSpread) { - code.appendLeft(end, ')'); + if (!inObject) { + code.appendLeft(previousEnd, ' {'); + } + code.update( + attributes.at(-1)?.end || previousEnd, + end, + ` children: ${renderedChildren > 1 ? '[' : ''}` + ); + const childrenClose = renderedChildren > 1 ? ']' : ''; + const closingElementStart = + parent instanceof JSXElement ? parent.closingElement!.start : parent.closingFragment!.start; + if (keyAttribute) { + const { value } = keyAttribute; + if (value) { + code.prependRight(value.start, `${childrenClose} }${closeObjectAssign}, `); + code.move(value.start, value.end, closingElementStart); + } else { + code.prependRight(closingElementStart, `${childrenClose} }${closeObjectAssign}, true`); + } + } else { + // We need to attach to the right as children are not rendered yet and + // this appendLeft will not append to things appended by the children + code.prependRight(closingElementStart, `${childrenClose} }${closeObjectAssign}`); } } else { - code.update(previousEnd, end, ')'); - } - // TODO Lukas this should be relative to the parent if there are children - if (keyAttribute) { - const { value } = keyAttribute; - // This will appear to the left of the moved code... - code.appendLeft(end, ', '); - if (value) { - if (selfClosing) { - // ...and this will appear to the right - code.appendLeft(value.end, ')'); + if (inObject) { + if (hasAttributes) { + code.appendLeft(previousEnd, ' '); } - code.move(value.start, value.end, end); + code.update(attributes.at(-1)?.end || previousEnd, end, '}' + closeObjectAssign); } else { - code.appendLeft(end, 'true)'); + code.update(previousEnd, end, ')'); + } + if (keyAttribute) { + const { value } = keyAttribute; + // This will appear to the left of the moved code... + code.appendLeft(end, ', '); + if (value) { + if (selfClosing) { + // ...and this will appear to the right + code.appendLeft(value.end, ')'); + } + code.move(value.start, value.end, end); + } else { + code.appendLeft(end, 'true'); + if (selfClosing) { + code.appendLeft(end, ')'); + } + } + } else if (selfClosing) { + code.appendLeft(end, ')'); } - } else if (selfClosing) { - code.appendLeft(end, ')'); } - - // if (hasSpread) { - // if (regularAttributes.length === 1) { - // code.appendLeft(nameEnd, ','); - // code.overwrite(attributes.at(-1)!.end, end, '', { contentOnly: true }); - // } else { - // code.appendLeft(nameEnd, ', Object.assign('); - // let inObject = false; - // if (!(regularAttributes[0] instanceof JSXSpreadAttribute)) { - // code.appendLeft(nameEnd, '{'); - // inObject = true; - // } - // for (let index = 1; index < regularAttributes.length; index++) { - // const attribute = regularAttributes[index]; - // if (attribute instanceof JSXSpreadAttribute) { - // if (inObject) { - // code.prependRight(attribute.start, '}, '); - // inObject = false; - // } else { - // code.appendLeft(regularAttributes[index - 1].end, ','); - // } - // } else { - // if (inObject) { - // code.appendLeft(regularAttributes[index - 1].end, ','); - // } else { - // code.appendLeft(regularAttributes[index - 1].end, ', {'); - // inObject = true; - // } - // } - // } - // if (inObject) { - // code.appendLeft(attributes.at(-1)!.end, ' }'); - // } - // code.overwrite(attributes.at(-1)!.end, end, ')', { contentOnly: true }); - // } - // } else if (regularAttributes.length > 0) { - // code.appendLeft(nameEnd, ', {'); - // for (let index = 0; index < regularAttributes.length - 1; index++) { - // code.appendLeft(regularAttributes[index].end, ', '); - // } - // code.overwrite(attributes.at(-1)!.end, end, ' }', { - // contentOnly: true - // }); - // } else if (keyAttribute) { - // code.remove(nameEnd, keyAttribute.start); - // code.overwrite(keyAttribute.end, end, `, {}`, { - // contentOnly: true - // }); - // } else { - // code.overwrite(nameEnd, end, `, {}`, { - // contentOnly: true - // }); - // } - // if (selfClosing) { - // if (keyAttribute) { - // const { value } = keyAttribute; - // // This will appear to the left of the moved code... - // code.appendLeft(end, ', '); - // if (value) { - // // ...and this will appear to the right - // code.appendLeft(value.end, ')'); - // code.move(value.start, value.end, end); - // } else { - // code.appendLeft(end, 'true)'); - // } - // } else { - // code.appendLeft(end, ')'); - // } - // } } } diff --git a/src/ast/nodes/shared/JSXOpeningBase.ts b/src/ast/nodes/shared/JSXOpeningBase.ts index c2653621790..23e0ab94344 100644 --- a/src/ast/nodes/shared/JSXOpeningBase.ts +++ b/src/ast/nodes/shared/JSXOpeningBase.ts @@ -1,4 +1,5 @@ import type { NormalizedJsxOptions } from '../../../rollup/types'; +import { getRenderedJsxChildren } from '../../../utils/jsx'; import type { InclusionContext } from '../../ExecutionContext'; import LocalVariable from '../../variables/LocalVariable'; import type Variable from '../../variables/Variable'; @@ -91,6 +92,6 @@ export default class JSXOpeningBase extends NodeBase { } } const parent = this.parent as JSXElement | JSXFragment; - return parent.children.length > 1 ? 'jsxs' : 'jsx'; + return getRenderedJsxChildren(parent.children) > 1 ? 'jsxs' : 'jsx'; } } diff --git a/src/utils/jsx.ts b/src/utils/jsx.ts new file mode 100644 index 00000000000..978cc0ba2a4 --- /dev/null +++ b/src/utils/jsx.ts @@ -0,0 +1,20 @@ +import type JSXElement from '../ast/nodes/JSXElement'; +import JSXEmptyExpression from '../ast/nodes/JSXEmptyExpression'; +import JSXExpressionContainer from '../ast/nodes/JSXExpressionContainer'; +import type JSXFragment from '../ast/nodes/JSXFragment'; +import type JSXSpreadChild from '../ast/nodes/JSXSpreadChild'; +import type JSXText from '../ast/nodes/JSXText'; + +export function getRenderedJsxChildren( + children: (JSXText | JSXExpressionContainer | JSXElement | JSXFragment | JSXSpreadChild)[] +) { + let renderedChildren = 0; + for (const child of children) { + if ( + !(child instanceof JSXExpressionContainer && child.expression instanceof JSXEmptyExpression) + ) { + renderedChildren++; + } + } + return renderedChildren; +} diff --git a/test/form/samples/jsx/preserves-jsx-attributes/_config.js b/test/form/samples/jsx/preserves-jsx-attributes/_config.js index 754b6da75d8..999308d2fe8 100644 --- a/test/form/samples/jsx/preserves-jsx-attributes/_config.js +++ b/test/form/samples/jsx/preserves-jsx-attributes/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js index 2b0c707ba7a..91dcafdf2a0 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-closing/_config.js b/test/form/samples/jsx/preserves-jsx-closing/_config.js index 9cb85863186..feabc92c211 100644 --- a/test/form/samples/jsx/preserves-jsx-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js index 207155a631b..bd7cbbd283e 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-expression/_config.js b/test/form/samples/jsx/preserves-jsx-expression/_config.js index a7a6c15cc6e..54463e778a0 100644 --- a/test/form/samples/jsx/preserves-jsx-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-fragment/_config.js b/test/form/samples/jsx/preserves-jsx-fragment/_config.js index 207155a631b..bd7cbbd283e 100644 --- a/test/form/samples/jsx/preserves-jsx-fragment/_config.js +++ b/test/form/samples/jsx/preserves-jsx-fragment/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-member-expression/_config.js b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js index 628a4fd9b42..f50ea52b60d 100644 --- a/test/form/samples/jsx/preserves-jsx-member-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX member expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-self-closing/_config.js b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js index dbf7d29c1c2..e9c22c2a5bf 100644 --- a/test/form/samples/jsx/preserves-jsx-self-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves self-closing JSX elements', options: { jsx: 'preserve' diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js index 7ee095abe33..708d3835bad 100644 --- a/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/_config.js b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js index f9f75d73aaf..48bdb770992 100644 --- a/test/form/samples/jsx/preserves-jsx-spread-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX spread children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-text/_config.js b/test/form/samples/jsx/preserves-jsx-text/_config.js index b653e85ee71..e6c2d2d3208 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_config.js +++ b/test/form/samples/jsx/preserves-jsx-text/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves JSX text', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-react-global/_config.js b/test/form/samples/jsx/preserves-react-global/_config.js index 46ca52230f7..7e103823e59 100644 --- a/test/form/samples/jsx/preserves-react-global/_config.js +++ b/test/form/samples/jsx/preserves-react-global/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves React variable when preserving JSX output', options: { jsx: { diff --git a/test/form/samples/jsx/preserves-react-internal/_config.js b/test/form/samples/jsx/preserves-react-internal/_config.js index e23f4cc4666..cdb797868b0 100644 --- a/test/form/samples/jsx/preserves-react-internal/_config.js +++ b/test/form/samples/jsx/preserves-react-internal/_config.js @@ -1,7 +1,7 @@ const path = require('node:path'); module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves internal React variable when preserving JSX output', options: { jsx: { diff --git a/test/form/samples/jsx/preserves-react/_config.js b/test/form/samples/jsx/preserves-react/_config.js index 863409c0ed8..37394afa887 100644 --- a/test/form/samples/jsx/preserves-react/_config.js +++ b/test/form/samples/jsx/preserves-react/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'preserves React variable when preserving JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js index 28d600c8510..a89325adf66 100644 --- a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-child/_config.js b/test/form/samples/jsx/transpiles-jsx-child/_config.js index 89b9be282e0..c47d4d8810d 100644 --- a/test/form/samples/jsx/transpiles-jsx-child/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-closing/_config.js index a54263d2370..b27d0e42cfc 100644 --- a/test/form/samples/jsx/transpiles-jsx-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js index 3f1ad493810..97e47e68922 100644 --- a/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-expression/_config.js index f0187c22730..f933678951f 100644 --- a/test/form/samples/jsx/transpiles-jsx-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-fragment/_config.js b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js index 3f1ad493810..97e47e68922 100644 --- a/test/form/samples/jsx/transpiles-jsx-fragment/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js index 9bf52de2829..fd6f237fa0e 100644 --- a/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX member expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js index dbf66b0a6cd..ec187f5af87 100644 --- a/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles self-closing JSX elements', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js index 56309e9fab1..713ba9abbc9 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js index 104ad1c6d7c..7debfe9e7f6 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX spread children', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-text/_config.js b/test/form/samples/jsx/transpiles-jsx-text/_config.js index ef037c71abb..2553bdabf6a 100644 --- a/test/form/samples/jsx/transpiles-jsx-text/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-text/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX text', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-react-global/_config.js b/test/form/samples/jsx/transpiles-react-global/_config.js index dfa379a12e9..36be476cd5a 100644 --- a/test/form/samples/jsx/transpiles-react-global/_config.js +++ b/test/form/samples/jsx/transpiles-react-global/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX for react', options: { jsx: { diff --git a/test/form/samples/jsx/transpiles-react-internal/_config.js b/test/form/samples/jsx/transpiles-react-internal/_config.js index 41a45f0932d..817d6be7c92 100644 --- a/test/form/samples/jsx/transpiles-react-internal/_config.js +++ b/test/form/samples/jsx/transpiles-react-internal/_config.js @@ -1,6 +1,6 @@ const path = require('node:path'); module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX for react', options: { jsx: { diff --git a/test/form/samples/jsx/transpiles-react-jsx/_expected.js b/test/form/samples/jsx/transpiles-react-jsx/_expected.js index e4e4aeabb14..b220c12cc49 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_expected.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_expected.js @@ -14,42 +14,53 @@ console.log(/*#__PURE__*/jsx(Foo, {}, "1")); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj))); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { x: "1" }))); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj), "1")); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj), true)); console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj))); console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj), "1")); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj), true)); console.log(/*#__PURE__*/jsx(Foo, {})); console.log(/*#__PURE__*/jsx(Foo, { x: "1" })); console.log(/*#__PURE__*/jsx(Foo, {}, "1")); +console.log(/*#__PURE__*/jsx(Foo, {}, true)); console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) })); console.log(/*#__PURE__*/jsx(Foo, { x: "1", children: /*#__PURE__*/jsx(Foo, {}) })); console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) }, "1")); +console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) }, true)); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { children: /*#__PURE__*/jsx(Foo, {}) }))); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { x: "1", children: /*#__PURE__*/jsx(Foo, {}) }))); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), "1")); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), true)); console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: /*#__PURE__*/jsx(Foo, {}) }))); console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), "1")); +console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), true)); console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) })); -console.log(/*#__PURE__*/jsx(_Fragment, {})); -console.log(/*#__PURE__*/jsx(_Fragment, { children: /*#__PURE__*/jsx(Foo, {}) })); +console.log(/*#__PURE__*/jsx(Fragment, {})); +console.log(/*#__PURE__*/jsx(Fragment, { children: /*#__PURE__*/jsx(Foo, {}) })); // jsxs console.log(/*#__PURE__*/jsxs(Foo, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); console.log(/*#__PURE__*/jsxs(Foo, { x: "1", children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); console.log(/*#__PURE__*/jsxs(Foo, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }, "1")); +console.log(/*#__PURE__*/jsxs(Foo, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }, true)); console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }))); console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { x: "1", children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }))); console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), "1")); +console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), true)); console.log(/*#__PURE__*/jsxs(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }))); console.log(/*#__PURE__*/jsxs(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), "1")); +console.log(/*#__PURE__*/jsxs(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), true)); -console.log(/*#__PURE__*/jsxs(_Fragment, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); +console.log(/*#__PURE__*/jsxs(Fragment, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); // createElement console.log(_createElement(Foo, Object.assign({}, obj, { key: "1" }))); +console.log(_createElement(Foo, Object.assign({}, obj, { key: true }))); console.log(_createElement(Foo, Object.assign({}, obj, obj, { x: "1", key: "1", y: "1" }))); +console.log(_createElement(Foo, Object.assign({}, obj, obj, { x: "1", key: true, y: "1" }))); console.log(_createElement(Foo, Object.assign({}, obj, { key: "1" }))); console.log(_createElement(Foo, Object.assign({}, obj, { key: "1" }), /*#__PURE__*/jsx(Foo, {}))); diff --git a/test/form/samples/jsx/transpiles-react-jsx/main.js b/test/form/samples/jsx/transpiles-react-jsx/main.js index 7da1f9e6297..e3346bf6393 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/main.js +++ b/test/form/samples/jsx/transpiles-react-jsx/main.js @@ -12,21 +12,27 @@ console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); +console.log(); console.log({/* comment */}{/* comment */}); @@ -37,16 +43,21 @@ console.log(<>); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); +console.log(); console.log(<>); // createElement console.log(); +console.log(); console.log(); +console.log(); console.log(); console.log(); diff --git a/test/form/samples/jsx/transpiles-react/_config.js b/test/form/samples/jsx/transpiles-react/_config.js index 0cd5a0ab494..ee724c087bb 100644 --- a/test/form/samples/jsx/transpiles-react/_config.js +++ b/test/form/samples/jsx/transpiles-react/_config.js @@ -1,5 +1,5 @@ module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'transpiles JSX for react', options: { external: ['react'], diff --git a/test/function/samples/jsx/missing-jsx-export/_config.js b/test/function/samples/jsx/missing-jsx-export/_config.js index 2aaf1a60842..d506a14f3f4 100644 --- a/test/function/samples/jsx/missing-jsx-export/_config.js +++ b/test/function/samples/jsx/missing-jsx-export/_config.js @@ -4,7 +4,7 @@ const ID_REACT = path.join(__dirname, 'react.js'); const ID_MAIN = path.join(__dirname, 'main.js'); module.exports = defineTest({ - solo: true, //x, + //solo: true, //x, description: 'throws when the JSX factory is not exported', options: { jsx: { From 3f208d542521167ad6c58e5200bd3acf3143a86f Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 3 Aug 2024 07:05:43 +0200 Subject: [PATCH 39/62] Fix fragment rendering --- src/ast/nodes/JSXFragment.ts | 7 +++++- src/ast/nodes/JSXOpeningElement.ts | 38 ++++++++++++----------------- src/ast/nodes/JSXOpeningFragment.ts | 31 ++++++++++++++++++----- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index eaa2cbcc535..38e644840c8 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -23,6 +23,7 @@ export default class JSXFragment extends NodeBase { super.render(code, options); } else { this.openingFragment.render(code, options); + let prependComma = mode === 'classic'; for (const child of this.children) { if ( child instanceof JSXExpressionContainer && @@ -31,7 +32,11 @@ export default class JSXFragment extends NodeBase { code.remove(child.start, child.end); } else { child.render(code, options); - code.appendRight(child.start, `, `); + if (prependComma) { + code.appendLeft(child.start, `, `); + } else { + prependComma = true; + } } } this.closingFragment?.render(code); diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index 6bfd6b28eff..32660846d92 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -3,8 +3,7 @@ import type { NormalizedJsxClassicOptions, NormalizedJsxOptions } from '../../ro import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXAttribute from './JSXAttribute'; -import JSXElement from './JSXElement'; -import type JSXFragment from './JSXFragment'; +import type JSXElement from './JSXElement'; import type JSXIdentifier from './JSXIdentifier'; import type JSXMemberExpression from './JSXMemberExpression'; import type JSXNamespacedName from './JSXNamespacedName'; @@ -51,16 +50,15 @@ export default class JSXOpeningElement extends JSXOpeningBase { start } = this; const [, ...nestedName] = factory.split('.'); - code.overwrite( + code.update( start, nameStart, - `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(`, - { contentOnly: true } + `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(` ); if (attributes.some(attribute => attribute instanceof JSXSpreadAttribute)) { if (attributes.length === 1) { code.appendLeft(nameEnd, ','); - code.overwrite(attributes[0].end, end, '', { contentOnly: true }); + code.update(attributes[0].end, end, ''); } else { code.appendLeft(nameEnd, ', Object.assign('); let inObject = false; @@ -89,20 +87,16 @@ export default class JSXOpeningElement extends JSXOpeningBase { if (inObject) { code.appendLeft(attributes.at(-1)!.end, ' }'); } - code.overwrite(attributes.at(-1)!.end, end, ')', { contentOnly: true }); + code.update(attributes.at(-1)!.end, end, ')'); } } else if (attributes.length > 0) { code.appendLeft(nameEnd, ', {'); for (let index = 0; index < attributes.length - 1; index++) { code.appendLeft(attributes[index].end, ', '); } - code.overwrite(attributes.at(-1)!.end, end, ' }', { - contentOnly: true - }); + code.update(attributes.at(-1)!.end, end, ' }'); } else { - code.overwrite(nameEnd, end, ', null', { - contentOnly: true - }); + code.update(nameEnd, end, ', null'); } if (selfClosing) { code.appendLeft(end, ')'); @@ -122,11 +116,10 @@ export default class JSXOpeningElement extends JSXOpeningBase { selfClosing, start } = this; - code.overwrite( + code.update( start, nameStart, - `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(`, - { contentOnly: true } + `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(` ); let keyAttribute: JSXAttribute | null = null; let hasSpread = false; @@ -164,7 +157,7 @@ export default class JSXOpeningElement extends JSXOpeningBase { } code.prependLeft(nameEnd, hasSpread ? ', Object.assign({' : ', {'); const closeObjectAssign = hasSpread ? ')' : ''; - const parent = this.parent as JSXElement | JSXFragment; + const parent = this.parent as JSXElement; const renderedChildren = getRenderedJsxChildren(parent.children); if (renderedChildren > 0) { if (hasAttributes) { @@ -179,20 +172,21 @@ export default class JSXOpeningElement extends JSXOpeningBase { ` children: ${renderedChildren > 1 ? '[' : ''}` ); const childrenClose = renderedChildren > 1 ? ']' : ''; - const closingElementStart = - parent instanceof JSXElement ? parent.closingElement!.start : parent.closingFragment!.start; if (keyAttribute) { const { value } = keyAttribute; if (value) { code.prependRight(value.start, `${childrenClose} }${closeObjectAssign}, `); - code.move(value.start, value.end, closingElementStart); + code.move(value.start, value.end, parent.closingElement!.start); } else { - code.prependRight(closingElementStart, `${childrenClose} }${closeObjectAssign}, true`); + code.prependRight( + parent.closingElement!.start, + `${childrenClose} }${closeObjectAssign}, true` + ); } } else { // We need to attach to the right as children are not rendered yet and // this appendLeft will not append to things appended by the children - code.prependRight(closingElementStart, `${childrenClose} }${closeObjectAssign}`); + code.prependRight(parent.closingElement!.start, `${childrenClose} }${closeObjectAssign}`); } } else { if (inObject) { diff --git a/src/ast/nodes/JSXOpeningFragment.ts b/src/ast/nodes/JSXOpeningFragment.ts index 41bf64ea516..405ef560a4a 100644 --- a/src/ast/nodes/JSXOpeningFragment.ts +++ b/src/ast/nodes/JSXOpeningFragment.ts @@ -1,8 +1,10 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../rollup/types'; +import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; import type { InclusionContext } from '../ExecutionContext'; import type Variable from '../variables/Variable'; +import type JSXFragment from './JSXFragment'; import type * as NodeType from './NodeType'; import type { InclusionOptions } from './shared/Expression'; import JSXOpeningBase from './shared/JSXOpeningBase'; @@ -44,12 +46,29 @@ export default class JSXOpeningFragment extends JSXOpeningBase { if (jsx.mode !== 'preserve') { const [, ...nestedFactory] = jsx.mode === 'classic' ? jsx.factory.split('.') : []; const [, ...nestedFragment] = jsx.mode === 'classic' ? jsx.fragment.split('.') : []; - code.overwrite( - this.start, - this.end, - `/*#__PURE__*/${[this.factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedFactory].join('.')}(${[this.fragmentVariable!.getName(getPropertyAccess, useOriginalName), ...nestedFragment].join('.')}, null`, - { contentOnly: true } - ); + const factory = [ + this.factoryVariable!.getName(getPropertyAccess, useOriginalName), + ...nestedFactory + ].join('.'); + const fragment = [ + this.fragmentVariable!.getName(getPropertyAccess, useOriginalName), + ...nestedFragment + ].join('.'); + code.update(this.start, this.end, `/*#__PURE__*/${factory}(${fragment}, `); + if (jsx.mode === 'classic') { + code.appendLeft(this.end, 'null'); + } else { + code.appendLeft(this.end, '{'); + const parent = this.parent as JSXFragment; + const renderedChildren = getRenderedJsxChildren(parent.children); + if (renderedChildren > 0) { + code.appendLeft(this.end, ` children: ${renderedChildren > 1 ? '[' : ''}`); + } + code.prependRight( + parent.closingFragment.start, + `${renderedChildren > 1 ? '] ' : renderedChildren > 0 ? ' ' : ''}}` + ); + } } } } From be3c7fda4dc855335479ba0bded004372da727cc Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 3 Aug 2024 07:25:49 +0200 Subject: [PATCH 40/62] Prepare for fallback rendering We still need to switch the arguments to old mode as well for the fallback case. --- src/Module.ts | 13 ++++++-- src/ast/nodes/JSXOpeningFragment.ts | 7 ++-- src/ast/nodes/shared/JSXOpeningBase.ts | 37 ++++++++++------------ src/rollup/types.d.ts | 5 +-- src/utils/options/normalizeInputOptions.ts | 4 ++- src/utils/options/options.ts | 4 ++- 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/Module.ts b/src/Module.ts index 25e6e7a33de..3b25c6d67ac 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -121,7 +121,7 @@ export interface AstContext { error: (properties: RollupLog, pos: number) => never; fileName: string; getExports: () => string[]; - getImportedJsxFactoryVariable: (baseName: string, pos: number) => Variable; + getImportedJsxFactoryVariable: (baseName: string, pos: number, importSource: string) => Variable; getModuleExecIndex: () => number; getModuleName: () => string; getNodeConstructor: (name: string) => typeof NodeBase; @@ -1158,6 +1158,10 @@ export default class Module { if (jsx.importSource && !this.sourcesWithAttributes.has(jsx.importSource)) { this.sourcesWithAttributes.set(jsx.importSource, EMPTY_OBJECT); } + // TODO Lukas is this needed? + if (jsx.mode === 'automatic' && !this.sourcesWithAttributes.has(jsx.jsxImportSource)) { + this.sourcesWithAttributes.set(jsx.jsxImportSource, EMPTY_OBJECT); + } } private addImportMeta(node: MetaProperty): void { @@ -1246,8 +1250,11 @@ export default class Module { } } - private getImportedJsxFactoryVariable(baseName: string, nodeStart: number): Variable { - const { importSource } = this.scope.context.options.jsx as NormalizedJsxOptions; + private getImportedJsxFactoryVariable( + baseName: string, + nodeStart: number, + importSource: string + ): Variable { const { id } = this.resolvedIds[importSource!]; const module = this.graph.modulesById.get(id)!; const [variable] = module.getVariableForExportName(baseName); diff --git a/src/ast/nodes/JSXOpeningFragment.ts b/src/ast/nodes/JSXOpeningFragment.ts index 405ef560a4a..f7a56238095 100644 --- a/src/ast/nodes/JSXOpeningFragment.ts +++ b/src/ast/nodes/JSXOpeningFragment.ts @@ -24,12 +24,15 @@ export default class JSXOpeningFragment extends JSXOpeningBase { ): void { if (!this.included) { const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - const fragment = jsx.mode === 'automatic' ? 'Fragment' : jsx.fragment; + const [fragment, importSource] = + jsx.mode === 'automatic' + ? ['Fragment', jsx.jsxImportSource] + : [jsx.fragment, jsx.importSource]; if (fragment != null) { this.fragmentVariable = this.getAndIncludeFactoryVariable( fragment, jsx.mode === 'preserve', - jsx.importSource + importSource ); } } diff --git a/src/ast/nodes/shared/JSXOpeningBase.ts b/src/ast/nodes/shared/JSXOpeningBase.ts index 23e0ab94344..a1bc4086ca8 100644 --- a/src/ast/nodes/shared/JSXOpeningBase.ts +++ b/src/ast/nodes/shared/JSXOpeningBase.ts @@ -22,25 +22,19 @@ export default class JSXOpeningBase extends NodeBase { if (!this.deoptimized) this.applyDeoptimizations(); if (!this.included) { const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - switch (jsx.mode) { - case 'preserve': - case 'classic': { - if (jsx.factory) { - this.factoryVariable = this.getAndIncludeFactoryVariable( - jsx.factory, - jsx.mode === 'preserve', - jsx.importSource - ); - } - break; - } - case 'automatic': { - this.factoryVariable = this.getAndIncludeFactoryVariable( - this.getAutomaticJsxFactoryName(), - false, - jsx.importSource - ); - } + const automaticFactory = jsx.mode === 'automatic' && this.getAutomaticJsxFactoryName(); + if (automaticFactory) { + this.factoryVariable = this.getAndIncludeFactoryVariable( + automaticFactory, + false, + jsx.jsxImportSource + ); + } else if (jsx.factory) { + this.factoryVariable = this.getAndIncludeFactoryVariable( + jsx.factory, + jsx.mode === 'preserve', + jsx.importSource + ); } } super.include(context, includeChildrenRecursively, options); @@ -61,7 +55,8 @@ export default class JSXOpeningBase extends NodeBase { if (importSource) { factoryVariable = this.scope.context.getImportedJsxFactoryVariable( nestedName ? 'default' : baseName, - this.start + this.start, + importSource ); if (preserve) { // This pretends we are accessing an included global variable of the same name @@ -88,7 +83,7 @@ export default class JSXOpeningBase extends NodeBase { if (attribute instanceof JSXSpreadAttribute) { hasSpread = true; } else if (hasSpread && attribute.name.name === 'key') { - return 'createElement'; + return null; } } const parent = this.parent as JSXElement | JSXFragment; diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index a58feebcee6..dcbc41a542e 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -544,9 +544,10 @@ interface NormalizedJsxClassicOptions { mode: 'classic'; } -// TODO Lukas createElement must be imported from "react" at the moment -> jsxImportSource for jsx(s) and Fragment, importSource + factory for createElement interface NormalizedJsxAutomaticOptions { - importSource: string; + factory: string; + importSource: string | null; + jsxImportSource: string; mode: 'automatic'; } diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index 43b55dc54b2..54452241ac8 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -123,7 +123,9 @@ const getJsx = (config: InputOptions): NormalizedInputOptions['jsx'] => { switch (configWithPreset.mode) { case 'automatic': { return { - importSource: configWithPreset.importSource || 'react/jsx-runtime', + factory: configWithPreset.factory || 'React.createElement', + importSource: configWithPreset.importSource || null, + jsxImportSource: configWithPreset.jsxImportSource || 'react/jsx-runtime', mode: 'automatic' }; } diff --git a/src/utils/options/options.ts b/src/utils/options/options.ts index ff3a76ce174..a459e4dfeea 100644 --- a/src/utils/options/options.ts +++ b/src/utils/options/options.ts @@ -159,7 +159,9 @@ export const jsxPresets: { mode: 'classic' }, 'react-jsx': { - importSource: 'react/jsx-runtime', + factory: 'React.createElement', + importSource: 'react', + jsxImportSource: 'react/jsx-runtime', mode: 'automatic' } }; From 2979bf1aa61a325f0016f66a324e073ca98da833 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 3 Aug 2024 07:27:12 +0200 Subject: [PATCH 41/62] Reenable tests for now --- test/form/samples/jsx/preserves-jsx-attributes/_config.js | 1 - test/form/samples/jsx/preserves-jsx-child/_config.js | 1 - test/form/samples/jsx/preserves-jsx-closing/_config.js | 1 - test/form/samples/jsx/preserves-jsx-empty-expression/_config.js | 1 - test/form/samples/jsx/preserves-jsx-expression/_config.js | 1 - test/form/samples/jsx/preserves-jsx-fragment/_config.js | 1 - test/form/samples/jsx/preserves-jsx-member-expression/_config.js | 1 - test/form/samples/jsx/preserves-jsx-self-closing/_config.js | 1 - test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js | 1 - test/form/samples/jsx/preserves-jsx-spread-child/_config.js | 1 - test/form/samples/jsx/preserves-jsx-text/_config.js | 1 - test/form/samples/jsx/preserves-react-global/_config.js | 1 - test/form/samples/jsx/preserves-react-internal/_config.js | 1 - test/form/samples/jsx/preserves-react/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-attributes/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-child/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-closing/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-expression/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-fragment/_config.js | 1 - .../form/samples/jsx/transpiles-jsx-member-expression/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-self-closing/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-spread-child/_config.js | 1 - test/form/samples/jsx/transpiles-jsx-text/_config.js | 1 - test/form/samples/jsx/transpiles-react-global/_config.js | 1 - test/form/samples/jsx/transpiles-react-internal/_config.js | 1 - test/form/samples/jsx/transpiles-react-jsx/_config.js | 1 - test/form/samples/jsx/transpiles-react/_config.js | 1 - test/function/samples/jsx/missing-jsx-export/_config.js | 1 - 30 files changed, 30 deletions(-) diff --git a/test/form/samples/jsx/preserves-jsx-attributes/_config.js b/test/form/samples/jsx/preserves-jsx-attributes/_config.js index 999308d2fe8..741ed769f87 100644 --- a/test/form/samples/jsx/preserves-jsx-attributes/_config.js +++ b/test/form/samples/jsx/preserves-jsx-attributes/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js index 91dcafdf2a0..6eb31e3795c 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-closing/_config.js b/test/form/samples/jsx/preserves-jsx-closing/_config.js index feabc92c211..b5f1855f6a3 100644 --- a/test/form/samples/jsx/preserves-jsx-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-closing/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js index bd7cbbd283e..1563f600507 100644 --- a/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-empty-expression/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-expression/_config.js b/test/form/samples/jsx/preserves-jsx-expression/_config.js index 54463e778a0..5d94a414623 100644 --- a/test/form/samples/jsx/preserves-jsx-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-expression/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-fragment/_config.js b/test/form/samples/jsx/preserves-jsx-fragment/_config.js index bd7cbbd283e..1563f600507 100644 --- a/test/form/samples/jsx/preserves-jsx-fragment/_config.js +++ b/test/form/samples/jsx/preserves-jsx-fragment/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-member-expression/_config.js b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js index f50ea52b60d..2b51fdc7286 100644 --- a/test/form/samples/jsx/preserves-jsx-member-expression/_config.js +++ b/test/form/samples/jsx/preserves-jsx-member-expression/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX member expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-self-closing/_config.js b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js index e9c22c2a5bf..a94325994ee 100644 --- a/test/form/samples/jsx/preserves-jsx-self-closing/_config.js +++ b/test/form/samples/jsx/preserves-jsx-self-closing/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves self-closing JSX elements', options: { jsx: 'preserve' diff --git a/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js index 708d3835bad..5554b472072 100644 --- a/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/preserves-jsx-spread-attribute/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-spread-child/_config.js b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js index 48bdb770992..e846a8043e6 100644 --- a/test/form/samples/jsx/preserves-jsx-spread-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-spread-child/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX spread children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-text/_config.js b/test/form/samples/jsx/preserves-jsx-text/_config.js index e6c2d2d3208..74acdb423be 100644 --- a/test/form/samples/jsx/preserves-jsx-text/_config.js +++ b/test/form/samples/jsx/preserves-jsx-text/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves JSX text', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-react-global/_config.js b/test/form/samples/jsx/preserves-react-global/_config.js index 7e103823e59..c694db34942 100644 --- a/test/form/samples/jsx/preserves-react-global/_config.js +++ b/test/form/samples/jsx/preserves-react-global/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves React variable when preserving JSX output', options: { jsx: { diff --git a/test/form/samples/jsx/preserves-react-internal/_config.js b/test/form/samples/jsx/preserves-react-internal/_config.js index cdb797868b0..4601d0902f0 100644 --- a/test/form/samples/jsx/preserves-react-internal/_config.js +++ b/test/form/samples/jsx/preserves-react-internal/_config.js @@ -1,7 +1,6 @@ const path = require('node:path'); module.exports = defineTest({ - //solo: true, //x, description: 'preserves internal React variable when preserving JSX output', options: { jsx: { diff --git a/test/form/samples/jsx/preserves-react/_config.js b/test/form/samples/jsx/preserves-react/_config.js index 37394afa887..ca4145a5e30 100644 --- a/test/form/samples/jsx/preserves-react/_config.js +++ b/test/form/samples/jsx/preserves-react/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'preserves React variable when preserving JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js index a89325adf66..6eec3cae05e 100644 --- a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-child/_config.js b/test/form/samples/jsx/transpiles-jsx-child/_config.js index c47d4d8810d..66790a15999 100644 --- a/test/form/samples/jsx/transpiles-jsx-child/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-child/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-closing/_config.js index b27d0e42cfc..719ece5beb1 100644 --- a/test/form/samples/jsx/transpiles-jsx-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-closing/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js index 97e47e68922..154660bc4ed 100644 --- a/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-empty-expression/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-expression/_config.js index f933678951f..217e03f576b 100644 --- a/test/form/samples/jsx/transpiles-jsx-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-expression/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-fragment/_config.js b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js index 97e47e68922..154660bc4ed 100644 --- a/test/form/samples/jsx/transpiles-jsx-fragment/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-fragment/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js index fd6f237fa0e..dfd4b69c2a6 100644 --- a/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-member-expression/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX member expressions', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js index ec187f5af87..ec1eb81a545 100644 --- a/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-self-closing/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles self-closing JSX elements', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js index 713ba9abbc9..edcac60d1e7 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js index 7debfe9e7f6..cc06baae2bd 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-child/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX spread children', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-text/_config.js b/test/form/samples/jsx/transpiles-jsx-text/_config.js index 2553bdabf6a..d3fcf6b7956 100644 --- a/test/form/samples/jsx/transpiles-jsx-text/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-text/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX text', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-react-global/_config.js b/test/form/samples/jsx/transpiles-react-global/_config.js index 36be476cd5a..3af41f24e69 100644 --- a/test/form/samples/jsx/transpiles-react-global/_config.js +++ b/test/form/samples/jsx/transpiles-react-global/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX for react', options: { jsx: { diff --git a/test/form/samples/jsx/transpiles-react-internal/_config.js b/test/form/samples/jsx/transpiles-react-internal/_config.js index 817d6be7c92..4a1583e82f8 100644 --- a/test/form/samples/jsx/transpiles-react-internal/_config.js +++ b/test/form/samples/jsx/transpiles-react-internal/_config.js @@ -1,6 +1,5 @@ const path = require('node:path'); module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX for react', options: { jsx: { diff --git a/test/form/samples/jsx/transpiles-react-jsx/_config.js b/test/form/samples/jsx/transpiles-react-jsx/_config.js index a144b877eb3..16f207347a8 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_config.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - solo: true, description: 'transpiles JSX for react', options: { external: ['react/jsx-runtime'], diff --git a/test/form/samples/jsx/transpiles-react/_config.js b/test/form/samples/jsx/transpiles-react/_config.js index ee724c087bb..4b546d0fdcd 100644 --- a/test/form/samples/jsx/transpiles-react/_config.js +++ b/test/form/samples/jsx/transpiles-react/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - //solo: true, //x, description: 'transpiles JSX for react', options: { external: ['react'], diff --git a/test/function/samples/jsx/missing-jsx-export/_config.js b/test/function/samples/jsx/missing-jsx-export/_config.js index d506a14f3f4..d814c6318ac 100644 --- a/test/function/samples/jsx/missing-jsx-export/_config.js +++ b/test/function/samples/jsx/missing-jsx-export/_config.js @@ -4,7 +4,6 @@ const ID_REACT = path.join(__dirname, 'react.js'); const ID_MAIN = path.join(__dirname, 'main.js'); module.exports = defineTest({ - //solo: true, //x, description: 'throws when the JSX factory is not exported', options: { jsx: { From eab88186ea9f275a12d18a6ff8323d271d939823 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 19 Aug 2024 11:11:58 +0200 Subject: [PATCH 42/62] Update linting --- .../src/ast_nodes/arrow_function_expression.rs | 2 +- rust/parse_ast/src/ast_nodes/assignment_expression.rs | 2 +- rust/parse_ast/src/ast_nodes/binary_expression.rs | 4 ++-- rust/parse_ast/src/ast_nodes/call_expression.rs | 2 +- rust/parse_ast/src/ast_nodes/for_of_statement.rs | 2 +- rust/parse_ast/src/ast_nodes/identifier.rs | 2 +- rust/parse_ast/src/ast_nodes/import_attribute.rs | 4 ++-- rust/parse_ast/src/ast_nodes/import_declaration.rs | 4 ++-- rust/parse_ast/src/ast_nodes/import_expression.rs | 4 ++-- rust/parse_ast/src/ast_nodes/jsx_empty_expression.rs | 2 +- rust/parse_ast/src/ast_nodes/jsx_member_expression.rs | 4 ++-- rust/parse_ast/src/ast_nodes/jsx_namespaced_name.rs | 4 ++-- rust/parse_ast/src/ast_nodes/jsx_opening_element.rs | 4 ++-- rust/parse_ast/src/ast_nodes/literal_boolean.rs | 2 +- rust/parse_ast/src/ast_nodes/member_expression.rs | 8 ++++---- rust/parse_ast/src/ast_nodes/meta_property.rs | 4 ++-- rust/parse_ast/src/ast_nodes/method_definition.rs | 2 +- rust/parse_ast/src/ast_nodes/new_expression.rs | 6 +++--- rust/parse_ast/src/ast_nodes/panic_error.rs | 4 ++-- rust/parse_ast/src/ast_nodes/parse_error.rs | 2 +- rust/parse_ast/src/ast_nodes/program.rs | 4 ++-- rust/parse_ast/src/ast_nodes/property.rs | 2 +- rust/parse_ast/src/ast_nodes/property_definition.rs | 4 ++-- rust/parse_ast/src/ast_nodes/rest_element.rs | 2 +- rust/parse_ast/src/ast_nodes/shared/class_node.rs | 4 ++-- rust/parse_ast/src/ast_nodes/shared/function_node.rs | 2 +- rust/parse_ast/src/ast_nodes/template_element.rs | 2 +- rust/parse_ast/src/ast_nodes/template_literal.rs | 4 ++-- rust/parse_ast/src/ast_nodes/try_statement.rs | 4 ++-- rust/parse_ast/src/ast_nodes/unary_expression.rs | 4 ++-- rust/parse_ast/src/ast_nodes/variable_declaration.rs | 10 +++++----- rust/parse_ast/src/ast_nodes/variable_declarator.rs | 4 ++-- rust/parse_ast/src/ast_nodes/yield_expression.rs | 2 +- rust/parse_ast/src/convert_ast/annotations.rs | 2 +- rust/parse_ast/src/convert_ast/converter.rs | 8 ++++---- .../src/convert_ast/converter/utf16_positions.rs | 2 +- rust/parse_ast/src/error_emit.rs | 2 +- 37 files changed, 65 insertions(+), 65 deletions(-) diff --git a/rust/parse_ast/src/ast_nodes/arrow_function_expression.rs b/rust/parse_ast/src/ast_nodes/arrow_function_expression.rs index 8ac6e1fd7bc..44fd2d76c9b 100644 --- a/rust/parse_ast/src/ast_nodes/arrow_function_expression.rs +++ b/rust/parse_ast/src/ast_nodes/arrow_function_expression.rs @@ -1,12 +1,12 @@ use swc_ecma_ast::{ArrowExpr, BlockStmtOrExpr}; use crate::convert_ast::annotations::AnnotationKind; -use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ ARROW_FUNCTION_EXPRESSION_ANNOTATIONS_OFFSET, ARROW_FUNCTION_EXPRESSION_BODY_OFFSET, ARROW_FUNCTION_EXPRESSION_PARAMS_OFFSET, ARROW_FUNCTION_EXPRESSION_RESERVED_BYTES, TYPE_ARROW_FUNCTION_EXPRESSION, }; +use crate::convert_ast::converter::{convert_annotation, AstConverter}; use crate::store_arrow_function_expression_flags; impl<'a> AstConverter<'a> { diff --git a/rust/parse_ast/src/ast_nodes/assignment_expression.rs b/rust/parse_ast/src/ast_nodes/assignment_expression.rs index 19c934e915b..4a696977db9 100644 --- a/rust/parse_ast/src/ast_nodes/assignment_expression.rs +++ b/rust/parse_ast/src/ast_nodes/assignment_expression.rs @@ -1,12 +1,12 @@ use swc_ecma_ast::{AssignExpr, AssignOp}; -use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ STRING_ADDASSIGN, STRING_ANDASSIGN, STRING_ASSIGN, STRING_BITANDASSIGN, STRING_BITORASSIGN, STRING_BITXORASSIGN, STRING_DIVASSIGN, STRING_EXPASSIGN, STRING_LSHIFTASSIGN, STRING_MODASSIGN, STRING_MULASSIGN, STRING_NULLISHASSIGN, STRING_ORASSIGN, STRING_RSHIFTASSIGN, STRING_SUBASSIGN, STRING_ZEROFILLRSHIFTASSIGN, }; +use crate::convert_ast::converter::AstConverter; use crate::store_assignment_expression; impl<'a> AstConverter<'a> { diff --git a/rust/parse_ast/src/ast_nodes/binary_expression.rs b/rust/parse_ast/src/ast_nodes/binary_expression.rs index 17ba3c67ce0..e4e17702be9 100644 --- a/rust/parse_ast/src/ast_nodes/binary_expression.rs +++ b/rust/parse_ast/src/ast_nodes/binary_expression.rs @@ -1,17 +1,17 @@ -use swc_ecma_ast::{BinaryOp, BinExpr}; +use swc_ecma_ast::{BinExpr, BinaryOp}; use crate::convert_ast::converter::ast_constants::{ BINARY_EXPRESSION_LEFT_OFFSET, BINARY_EXPRESSION_OPERATOR_OFFSET, BINARY_EXPRESSION_RESERVED_BYTES, BINARY_EXPRESSION_RIGHT_OFFSET, TYPE_BINARY_EXPRESSION, TYPE_LOGICAL_EXPRESSION, }; -use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ STRING_ADD, STRING_BITAND, STRING_BITOR, STRING_BITXOR, STRING_DIV, STRING_EQEQ, STRING_EQEQEQ, STRING_EXP, STRING_GT, STRING_GTEQ, STRING_IN, STRING_INSTANCEOF, STRING_LOGICALAND, STRING_LOGICALOR, STRING_LSHIFT, STRING_LT, STRING_LTEQ, STRING_MOD, STRING_MUL, STRING_NOTEQ, STRING_NOTEQEQ, STRING_NULLISHCOALESCING, STRING_RSHIFT, STRING_SUB, STRING_ZEROFILLRSHIFT, }; +use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { pub(crate) fn store_binary_expression(&mut self, binary_expression: &BinExpr) { diff --git a/rust/parse_ast/src/ast_nodes/call_expression.rs b/rust/parse_ast/src/ast_nodes/call_expression.rs index 30916d872f5..e5dff9ea97a 100644 --- a/rust/parse_ast/src/ast_nodes/call_expression.rs +++ b/rust/parse_ast/src/ast_nodes/call_expression.rs @@ -2,11 +2,11 @@ use swc_common::Span; use swc_ecma_ast::{Expr, ExprOrSpread, OptCall, Super}; use crate::convert_ast::annotations::AnnotationKind; -use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ CALL_EXPRESSION_ANNOTATIONS_OFFSET, CALL_EXPRESSION_ARGUMENTS_OFFSET, CALL_EXPRESSION_CALLEE_OFFSET, CALL_EXPRESSION_RESERVED_BYTES, TYPE_CALL_EXPRESSION, }; +use crate::convert_ast::converter::{convert_annotation, AstConverter}; use crate::store_call_expression_flags; impl<'a> AstConverter<'a> { diff --git a/rust/parse_ast/src/ast_nodes/for_of_statement.rs b/rust/parse_ast/src/ast_nodes/for_of_statement.rs index 5602cba3dac..eb27dd7e071 100644 --- a/rust/parse_ast/src/ast_nodes/for_of_statement.rs +++ b/rust/parse_ast/src/ast_nodes/for_of_statement.rs @@ -1,7 +1,7 @@ use swc_ecma_ast::ForOfStmt; -use crate::{store_for_of_statement, store_for_of_statement_flags}; use crate::convert_ast::converter::AstConverter; +use crate::{store_for_of_statement, store_for_of_statement_flags}; impl<'a> AstConverter<'a> { pub(crate) fn store_for_of_statement(&mut self, for_of_statement: &ForOfStmt) { diff --git a/rust/parse_ast/src/ast_nodes/identifier.rs b/rust/parse_ast/src/ast_nodes/identifier.rs index 553a5fc3cc0..c42b21574ef 100644 --- a/rust/parse_ast/src/ast_nodes/identifier.rs +++ b/rust/parse_ast/src/ast_nodes/identifier.rs @@ -1,7 +1,7 @@ use swc_ecma_ast::{BindingIdent, Ident, IdentName}; use crate::convert_ast::converter::ast_constants::{ - IDENTIFIER_NAME_OFFSET, IDENTIFIER_RESERVED_BYTES, TYPE_IDENTIFIER, + IDENTIFIER_NAME_OFFSET, IDENTIFIER_RESERVED_BYTES, TYPE_IDENTIFIER, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/import_attribute.rs b/rust/parse_ast/src/ast_nodes/import_attribute.rs index 0bd4187886f..fc1842961e7 100644 --- a/rust/parse_ast/src/ast_nodes/import_attribute.rs +++ b/rust/parse_ast/src/ast_nodes/import_attribute.rs @@ -2,8 +2,8 @@ use swc_common::Spanned; use swc_ecma_ast::{KeyValueProp, ObjectLit, Prop, PropOrSpread}; use crate::convert_ast::converter::ast_constants::{ - IMPORT_ATTRIBUTE_KEY_OFFSET, IMPORT_ATTRIBUTE_RESERVED_BYTES, IMPORT_ATTRIBUTE_VALUE_OFFSET, - TYPE_IMPORT_ATTRIBUTE, + IMPORT_ATTRIBUTE_KEY_OFFSET, IMPORT_ATTRIBUTE_RESERVED_BYTES, IMPORT_ATTRIBUTE_VALUE_OFFSET, + TYPE_IMPORT_ATTRIBUTE, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/import_declaration.rs b/rust/parse_ast/src/ast_nodes/import_declaration.rs index 0734b38a9df..99890338d44 100644 --- a/rust/parse_ast/src/ast_nodes/import_declaration.rs +++ b/rust/parse_ast/src/ast_nodes/import_declaration.rs @@ -1,8 +1,8 @@ use swc_ecma_ast::ImportDecl; use crate::convert_ast::converter::ast_constants::{ - IMPORT_DECLARATION_ATTRIBUTES_OFFSET, IMPORT_DECLARATION_RESERVED_BYTES, - IMPORT_DECLARATION_SOURCE_OFFSET, IMPORT_DECLARATION_SPECIFIERS_OFFSET, TYPE_IMPORT_DECLARATION, + IMPORT_DECLARATION_ATTRIBUTES_OFFSET, IMPORT_DECLARATION_RESERVED_BYTES, + IMPORT_DECLARATION_SOURCE_OFFSET, IMPORT_DECLARATION_SPECIFIERS_OFFSET, TYPE_IMPORT_DECLARATION, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/import_expression.rs b/rust/parse_ast/src/ast_nodes/import_expression.rs index 966623e9ec3..19cff3f0d19 100644 --- a/rust/parse_ast/src/ast_nodes/import_expression.rs +++ b/rust/parse_ast/src/ast_nodes/import_expression.rs @@ -2,8 +2,8 @@ use swc_common::Span; use swc_ecma_ast::ExprOrSpread; use crate::convert_ast::converter::ast_constants::{ - IMPORT_EXPRESSION_OPTIONS_OFFSET, IMPORT_EXPRESSION_RESERVED_BYTES, - IMPORT_EXPRESSION_SOURCE_OFFSET, TYPE_IMPORT_EXPRESSION, + IMPORT_EXPRESSION_OPTIONS_OFFSET, IMPORT_EXPRESSION_RESERVED_BYTES, + IMPORT_EXPRESSION_SOURCE_OFFSET, TYPE_IMPORT_EXPRESSION, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/jsx_empty_expression.rs b/rust/parse_ast/src/ast_nodes/jsx_empty_expression.rs index c0b80dd582a..5b33e034e11 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_empty_expression.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_empty_expression.rs @@ -1,5 +1,5 @@ use crate::convert_ast::converter::ast_constants::{ - JSX_EMPTY_EXPRESSION_RESERVED_BYTES, TYPE_JSX_EMPTY_EXPRESSION, + JSX_EMPTY_EXPRESSION_RESERVED_BYTES, TYPE_JSX_EMPTY_EXPRESSION, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/jsx_member_expression.rs b/rust/parse_ast/src/ast_nodes/jsx_member_expression.rs index bb006ef2687..b31460e0b07 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_member_expression.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_member_expression.rs @@ -1,8 +1,8 @@ use swc_ecma_ast::JSXMemberExpr; use crate::convert_ast::converter::ast_constants::{ - JSX_MEMBER_EXPRESSION_OBJECT_OFFSET, JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET, - JSX_MEMBER_EXPRESSION_RESERVED_BYTES, TYPE_JSX_MEMBER_EXPRESSION, + JSX_MEMBER_EXPRESSION_OBJECT_OFFSET, JSX_MEMBER_EXPRESSION_PROPERTY_OFFSET, + JSX_MEMBER_EXPRESSION_RESERVED_BYTES, TYPE_JSX_MEMBER_EXPRESSION, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/jsx_namespaced_name.rs b/rust/parse_ast/src/ast_nodes/jsx_namespaced_name.rs index 6a81c53cd2c..ed61746af50 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_namespaced_name.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_namespaced_name.rs @@ -1,8 +1,8 @@ use swc_ecma_ast::JSXNamespacedName; use crate::convert_ast::converter::ast_constants::{ - JSX_NAMESPACED_NAME_NAME_OFFSET, JSX_NAMESPACED_NAME_NAMESPACE_OFFSET, - JSX_NAMESPACED_NAME_RESERVED_BYTES, TYPE_JSX_NAMESPACED_NAME, + JSX_NAMESPACED_NAME_NAMESPACE_OFFSET, JSX_NAMESPACED_NAME_NAME_OFFSET, + JSX_NAMESPACED_NAME_RESERVED_BYTES, TYPE_JSX_NAMESPACED_NAME, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/jsx_opening_element.rs b/rust/parse_ast/src/ast_nodes/jsx_opening_element.rs index c7d0e0b32ed..1bd4b1025b1 100644 --- a/rust/parse_ast/src/ast_nodes/jsx_opening_element.rs +++ b/rust/parse_ast/src/ast_nodes/jsx_opening_element.rs @@ -2,8 +2,8 @@ use swc_common::Spanned; use swc_ecma_ast::JSXOpeningElement; use crate::convert_ast::converter::ast_constants::{ - JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, - JSX_OPENING_ELEMENT_RESERVED_BYTES, TYPE_JSX_OPENING_ELEMENT, + JSX_OPENING_ELEMENT_ATTRIBUTES_OFFSET, JSX_OPENING_ELEMENT_NAME_OFFSET, + JSX_OPENING_ELEMENT_RESERVED_BYTES, TYPE_JSX_OPENING_ELEMENT, }; use crate::convert_ast::converter::AstConverter; use crate::store_jsx_opening_element_flags; diff --git a/rust/parse_ast/src/ast_nodes/literal_boolean.rs b/rust/parse_ast/src/ast_nodes/literal_boolean.rs index 7c9768ee261..41e22f75c31 100644 --- a/rust/parse_ast/src/ast_nodes/literal_boolean.rs +++ b/rust/parse_ast/src/ast_nodes/literal_boolean.rs @@ -1,7 +1,7 @@ use swc_ecma_ast::Bool; -use crate::{store_literal_boolean, store_literal_boolean_flags}; use crate::convert_ast::converter::AstConverter; +use crate::{store_literal_boolean, store_literal_boolean_flags}; impl<'a> AstConverter<'a> { pub(crate) fn store_literal_boolean(&mut self, literal: &Bool) { diff --git a/rust/parse_ast/src/ast_nodes/member_expression.rs b/rust/parse_ast/src/ast_nodes/member_expression.rs index f0eb33a684e..6b0b23db2e7 100644 --- a/rust/parse_ast/src/ast_nodes/member_expression.rs +++ b/rust/parse_ast/src/ast_nodes/member_expression.rs @@ -1,12 +1,12 @@ use swc_common::Span; use swc_ecma_ast::{ - ComputedPropName, Expr, IdentName, MemberExpr, MemberProp, PrivateName, Super, SuperProp, - SuperPropExpr, + ComputedPropName, Expr, IdentName, MemberExpr, MemberProp, PrivateName, Super, SuperProp, + SuperPropExpr, }; use crate::convert_ast::converter::ast_constants::{ - MEMBER_EXPRESSION_OBJECT_OFFSET, MEMBER_EXPRESSION_PROPERTY_OFFSET, - MEMBER_EXPRESSION_RESERVED_BYTES, TYPE_MEMBER_EXPRESSION, + MEMBER_EXPRESSION_OBJECT_OFFSET, MEMBER_EXPRESSION_PROPERTY_OFFSET, + MEMBER_EXPRESSION_RESERVED_BYTES, TYPE_MEMBER_EXPRESSION, }; use crate::convert_ast::converter::AstConverter; use crate::store_member_expression_flags; diff --git a/rust/parse_ast/src/ast_nodes/meta_property.rs b/rust/parse_ast/src/ast_nodes/meta_property.rs index 5028e01c4e8..35d4d826085 100644 --- a/rust/parse_ast/src/ast_nodes/meta_property.rs +++ b/rust/parse_ast/src/ast_nodes/meta_property.rs @@ -1,8 +1,8 @@ use swc_ecma_ast::{MetaPropExpr, MetaPropKind}; use crate::convert_ast::converter::ast_constants::{ - META_PROPERTY_META_OFFSET, META_PROPERTY_PROPERTY_OFFSET, META_PROPERTY_RESERVED_BYTES, - TYPE_META_PROPERTY, + META_PROPERTY_META_OFFSET, META_PROPERTY_PROPERTY_OFFSET, META_PROPERTY_RESERVED_BYTES, + TYPE_META_PROPERTY, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/method_definition.rs b/rust/parse_ast/src/ast_nodes/method_definition.rs index c17eed5a613..fd5b8d02102 100644 --- a/rust/parse_ast/src/ast_nodes/method_definition.rs +++ b/rust/parse_ast/src/ast_nodes/method_definition.rs @@ -10,10 +10,10 @@ use crate::convert_ast::converter::ast_constants::{ METHOD_DEFINITION_RESERVED_BYTES, METHOD_DEFINITION_VALUE_OFFSET, TYPE_FUNCTION_EXPRESSION, TYPE_METHOD_DEFINITION, }; -use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ STRING_CONSTRUCTOR, STRING_GET, STRING_METHOD, STRING_SET, }; +use crate::convert_ast::converter::AstConverter; use crate::store_method_definition_flags; impl<'a> AstConverter<'a> { diff --git a/rust/parse_ast/src/ast_nodes/new_expression.rs b/rust/parse_ast/src/ast_nodes/new_expression.rs index 00a5629ff77..20a01e21e1f 100644 --- a/rust/parse_ast/src/ast_nodes/new_expression.rs +++ b/rust/parse_ast/src/ast_nodes/new_expression.rs @@ -1,11 +1,11 @@ use swc_ecma_ast::NewExpr; use crate::convert_ast::annotations::AnnotationKind; -use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ - NEW_EXPRESSION_ANNOTATIONS_OFFSET, NEW_EXPRESSION_ARGUMENTS_OFFSET, NEW_EXPRESSION_CALLEE_OFFSET, - NEW_EXPRESSION_RESERVED_BYTES, TYPE_NEW_EXPRESSION, + NEW_EXPRESSION_ANNOTATIONS_OFFSET, NEW_EXPRESSION_ARGUMENTS_OFFSET, NEW_EXPRESSION_CALLEE_OFFSET, + NEW_EXPRESSION_RESERVED_BYTES, TYPE_NEW_EXPRESSION, }; +use crate::convert_ast::converter::{convert_annotation, AstConverter}; impl<'a> AstConverter<'a> { pub(crate) fn store_new_expression(&mut self, new_expression: &NewExpr) { diff --git a/rust/parse_ast/src/ast_nodes/panic_error.rs b/rust/parse_ast/src/ast_nodes/panic_error.rs index e01b606763d..bf290bcb4d7 100644 --- a/rust/parse_ast/src/ast_nodes/panic_error.rs +++ b/rust/parse_ast/src/ast_nodes/panic_error.rs @@ -1,7 +1,7 @@ -use crate::convert_ast::converter::{convert_string, update_reference_position}; use crate::convert_ast::converter::ast_constants::{ - PANIC_ERROR_MESSAGE_OFFSET, PANIC_ERROR_RESERVED_BYTES, TYPE_PANIC_ERROR, + PANIC_ERROR_MESSAGE_OFFSET, PANIC_ERROR_RESERVED_BYTES, TYPE_PANIC_ERROR, }; +use crate::convert_ast::converter::{convert_string, update_reference_position}; pub(crate) fn get_panic_error_buffer(message: &str) -> Vec { // type diff --git a/rust/parse_ast/src/ast_nodes/parse_error.rs b/rust/parse_ast/src/ast_nodes/parse_error.rs index b17c5c2c420..22026546025 100644 --- a/rust/parse_ast/src/ast_nodes/parse_error.rs +++ b/rust/parse_ast/src/ast_nodes/parse_error.rs @@ -1,5 +1,5 @@ use crate::convert_ast::converter::ast_constants::{ - PARSE_ERROR_MESSAGE_OFFSET, PARSE_ERROR_RESERVED_BYTES, TYPE_PARSE_ERROR, + PARSE_ERROR_MESSAGE_OFFSET, PARSE_ERROR_RESERVED_BYTES, TYPE_PARSE_ERROR, }; use crate::convert_ast::converter::update_reference_position; diff --git a/rust/parse_ast/src/ast_nodes/program.rs b/rust/parse_ast/src/ast_nodes/program.rs index 001c8e67344..f83106328a9 100644 --- a/rust/parse_ast/src/ast_nodes/program.rs +++ b/rust/parse_ast/src/ast_nodes/program.rs @@ -1,9 +1,9 @@ use swc_ecma_ast::{Expr, Lit, ModuleItem, Program, Stmt}; -use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ - PROGRAM_BODY_OFFSET, PROGRAM_INVALID_ANNOTATIONS_OFFSET, PROGRAM_RESERVED_BYTES, TYPE_PROGRAM, + PROGRAM_BODY_OFFSET, PROGRAM_INVALID_ANNOTATIONS_OFFSET, PROGRAM_RESERVED_BYTES, TYPE_PROGRAM, }; +use crate::convert_ast::converter::{convert_annotation, AstConverter}; impl<'a> AstConverter<'a> { pub(crate) fn store_program(&mut self, body: ModuleItemsOrStatements) { diff --git a/rust/parse_ast/src/ast_nodes/property.rs b/rust/parse_ast/src/ast_nodes/property.rs index 883771b20e1..fda0288293b 100644 --- a/rust/parse_ast/src/ast_nodes/property.rs +++ b/rust/parse_ast/src/ast_nodes/property.rs @@ -10,8 +10,8 @@ use crate::convert_ast::converter::ast_constants::{ PROPERTY_KEY_OFFSET, PROPERTY_KIND_OFFSET, PROPERTY_RESERVED_BYTES, PROPERTY_VALUE_OFFSET, TYPE_FUNCTION_EXPRESSION, TYPE_PROPERTY, }; -use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{STRING_GET, STRING_INIT, STRING_SET}; +use crate::convert_ast::converter::AstConverter; use crate::store_property_flags; impl<'a> AstConverter<'a> { diff --git a/rust/parse_ast/src/ast_nodes/property_definition.rs b/rust/parse_ast/src/ast_nodes/property_definition.rs index 33c310c44f0..4ef508d7270 100644 --- a/rust/parse_ast/src/ast_nodes/property_definition.rs +++ b/rust/parse_ast/src/ast_nodes/property_definition.rs @@ -3,8 +3,8 @@ use swc_ecma_ast::{ClassProp, Decorator, Expr, PrivateProp, PropName}; use crate::ast_nodes::method_definition::PropOrPrivateName; use crate::convert_ast::converter::ast_constants::{ - PROPERTY_DEFINITION_DECORATORS_OFFSET, PROPERTY_DEFINITION_KEY_OFFSET, - PROPERTY_DEFINITION_RESERVED_BYTES, PROPERTY_DEFINITION_VALUE_OFFSET, TYPE_PROPERTY_DEFINITION, + PROPERTY_DEFINITION_DECORATORS_OFFSET, PROPERTY_DEFINITION_KEY_OFFSET, + PROPERTY_DEFINITION_RESERVED_BYTES, PROPERTY_DEFINITION_VALUE_OFFSET, TYPE_PROPERTY_DEFINITION, }; use crate::convert_ast::converter::AstConverter; use crate::store_property_definition_flags; diff --git a/rust/parse_ast/src/ast_nodes/rest_element.rs b/rust/parse_ast/src/ast_nodes/rest_element.rs index 31124013a26..9176410c24a 100644 --- a/rust/parse_ast/src/ast_nodes/rest_element.rs +++ b/rust/parse_ast/src/ast_nodes/rest_element.rs @@ -1,7 +1,7 @@ use swc_ecma_ast::RestPat; use crate::convert_ast::converter::ast_constants::{ - REST_ELEMENT_ARGUMENT_OFFSET, REST_ELEMENT_RESERVED_BYTES, TYPE_REST_ELEMENT, + REST_ELEMENT_ARGUMENT_OFFSET, REST_ELEMENT_RESERVED_BYTES, TYPE_REST_ELEMENT, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/shared/class_node.rs b/rust/parse_ast/src/ast_nodes/shared/class_node.rs index 83abd0d7148..068b7aaba5b 100644 --- a/rust/parse_ast/src/ast_nodes/shared/class_node.rs +++ b/rust/parse_ast/src/ast_nodes/shared/class_node.rs @@ -3,8 +3,8 @@ use swc_ecma_ast::{Class, Ident}; use crate::convert_ast::converter::analyze_code::find_first_occurrence_outside_comment; use crate::convert_ast::converter::ast_constants::{ - CLASS_DECLARATION_BODY_OFFSET, CLASS_DECLARATION_DECORATORS_OFFSET, CLASS_DECLARATION_ID_OFFSET, - CLASS_DECLARATION_RESERVED_BYTES, CLASS_DECLARATION_SUPER_CLASS_OFFSET, + CLASS_DECLARATION_BODY_OFFSET, CLASS_DECLARATION_DECORATORS_OFFSET, CLASS_DECLARATION_ID_OFFSET, + CLASS_DECLARATION_RESERVED_BYTES, CLASS_DECLARATION_SUPER_CLASS_OFFSET, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/shared/function_node.rs b/rust/parse_ast/src/ast_nodes/shared/function_node.rs index 739597134d5..665411e7203 100644 --- a/rust/parse_ast/src/ast_nodes/shared/function_node.rs +++ b/rust/parse_ast/src/ast_nodes/shared/function_node.rs @@ -1,12 +1,12 @@ use swc_ecma_ast::{BlockStmt, Function, Ident, Pat}; use crate::convert_ast::annotations::AnnotationKind; -use crate::convert_ast::converter::{AstConverter, convert_annotation}; use crate::convert_ast::converter::ast_constants::{ FUNCTION_DECLARATION_ANNOTATIONS_OFFSET, FUNCTION_DECLARATION_BODY_OFFSET, FUNCTION_DECLARATION_ID_OFFSET, FUNCTION_DECLARATION_PARAMS_OFFSET, FUNCTION_DECLARATION_RESERVED_BYTES, }; +use crate::convert_ast::converter::{convert_annotation, AstConverter}; use crate::store_function_declaration_flags; impl<'a> AstConverter<'a> { diff --git a/rust/parse_ast/src/ast_nodes/template_element.rs b/rust/parse_ast/src/ast_nodes/template_element.rs index 23346d9388d..ee93394759a 100644 --- a/rust/parse_ast/src/ast_nodes/template_element.rs +++ b/rust/parse_ast/src/ast_nodes/template_element.rs @@ -1,7 +1,7 @@ use swc_ecma_ast::TplElement; -use crate::{store_template_element, store_template_element_flags}; use crate::convert_ast::converter::AstConverter; +use crate::{store_template_element, store_template_element_flags}; impl<'a> AstConverter<'a> { pub(crate) fn store_template_element(&mut self, template_element: &TplElement) { diff --git a/rust/parse_ast/src/ast_nodes/template_literal.rs b/rust/parse_ast/src/ast_nodes/template_literal.rs index 39c1f83d85b..a584df67806 100644 --- a/rust/parse_ast/src/ast_nodes/template_literal.rs +++ b/rust/parse_ast/src/ast_nodes/template_literal.rs @@ -1,8 +1,8 @@ use swc_ecma_ast::Tpl; use crate::convert_ast::converter::ast_constants::{ - TEMPLATE_LITERAL_EXPRESSIONS_OFFSET, TEMPLATE_LITERAL_QUASIS_OFFSET, - TEMPLATE_LITERAL_RESERVED_BYTES, TYPE_TEMPLATE_LITERAL, + TEMPLATE_LITERAL_EXPRESSIONS_OFFSET, TEMPLATE_LITERAL_QUASIS_OFFSET, + TEMPLATE_LITERAL_RESERVED_BYTES, TYPE_TEMPLATE_LITERAL, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/try_statement.rs b/rust/parse_ast/src/ast_nodes/try_statement.rs index e49cae9288e..53743332781 100644 --- a/rust/parse_ast/src/ast_nodes/try_statement.rs +++ b/rust/parse_ast/src/ast_nodes/try_statement.rs @@ -1,8 +1,8 @@ use swc_ecma_ast::TryStmt; use crate::convert_ast::converter::ast_constants::{ - TRY_STATEMENT_BLOCK_OFFSET, TRY_STATEMENT_FINALIZER_OFFSET, TRY_STATEMENT_HANDLER_OFFSET, - TRY_STATEMENT_RESERVED_BYTES, TYPE_TRY_STATEMENT, + TRY_STATEMENT_BLOCK_OFFSET, TRY_STATEMENT_FINALIZER_OFFSET, TRY_STATEMENT_HANDLER_OFFSET, + TRY_STATEMENT_RESERVED_BYTES, TYPE_TRY_STATEMENT, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/unary_expression.rs b/rust/parse_ast/src/ast_nodes/unary_expression.rs index b0c01849286..34f5c9a8120 100644 --- a/rust/parse_ast/src/ast_nodes/unary_expression.rs +++ b/rust/parse_ast/src/ast_nodes/unary_expression.rs @@ -1,9 +1,9 @@ use swc_ecma_ast::{UnaryExpr, UnaryOp}; -use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ - STRING_BANG, STRING_DELETE, STRING_MINUS, STRING_PLUS, STRING_TILDE, STRING_TYPEOF, STRING_VOID, + STRING_BANG, STRING_DELETE, STRING_MINUS, STRING_PLUS, STRING_TILDE, STRING_TYPEOF, STRING_VOID, }; +use crate::convert_ast::converter::AstConverter; use crate::store_unary_expression; impl<'a> AstConverter<'a> { diff --git a/rust/parse_ast/src/ast_nodes/variable_declaration.rs b/rust/parse_ast/src/ast_nodes/variable_declaration.rs index a0fe597055c..9dc4760d8f1 100644 --- a/rust/parse_ast/src/ast_nodes/variable_declaration.rs +++ b/rust/parse_ast/src/ast_nodes/variable_declaration.rs @@ -1,14 +1,14 @@ use swc_common::Span; -use swc_ecma_ast::{UsingDecl, VarDecl, VarDeclarator, VarDeclKind}; +use swc_ecma_ast::{UsingDecl, VarDecl, VarDeclKind, VarDeclarator}; use crate::convert_ast::converter::ast_constants::{ - TYPE_VARIABLE_DECLARATION, VARIABLE_DECLARATION_DECLARATIONS_OFFSET, - VARIABLE_DECLARATION_KIND_OFFSET, VARIABLE_DECLARATION_RESERVED_BYTES, + TYPE_VARIABLE_DECLARATION, VARIABLE_DECLARATION_DECLARATIONS_OFFSET, + VARIABLE_DECLARATION_KIND_OFFSET, VARIABLE_DECLARATION_RESERVED_BYTES, }; -use crate::convert_ast::converter::AstConverter; use crate::convert_ast::converter::string_constants::{ - STRING_AWAIT_USING, STRING_CONST, STRING_LET, STRING_USING, STRING_VAR, + STRING_AWAIT_USING, STRING_CONST, STRING_LET, STRING_USING, STRING_VAR, }; +use crate::convert_ast::converter::AstConverter; impl<'a> AstConverter<'a> { pub(crate) fn store_variable_declaration(&mut self, variable_declaration: &VariableDeclaration) { diff --git a/rust/parse_ast/src/ast_nodes/variable_declarator.rs b/rust/parse_ast/src/ast_nodes/variable_declarator.rs index 552acfcaa44..317b1b29e9a 100644 --- a/rust/parse_ast/src/ast_nodes/variable_declarator.rs +++ b/rust/parse_ast/src/ast_nodes/variable_declarator.rs @@ -2,8 +2,8 @@ use swc_ecma_ast::{Expr, VarDeclarator}; use crate::convert_ast::annotations::AnnotationKind; use crate::convert_ast::converter::ast_constants::{ - TYPE_VARIABLE_DECLARATOR, VARIABLE_DECLARATOR_ID_OFFSET, VARIABLE_DECLARATOR_INIT_OFFSET, - VARIABLE_DECLARATOR_RESERVED_BYTES, + TYPE_VARIABLE_DECLARATOR, VARIABLE_DECLARATOR_ID_OFFSET, VARIABLE_DECLARATOR_INIT_OFFSET, + VARIABLE_DECLARATOR_RESERVED_BYTES, }; use crate::convert_ast::converter::AstConverter; diff --git a/rust/parse_ast/src/ast_nodes/yield_expression.rs b/rust/parse_ast/src/ast_nodes/yield_expression.rs index 99910d3078c..96065311331 100644 --- a/rust/parse_ast/src/ast_nodes/yield_expression.rs +++ b/rust/parse_ast/src/ast_nodes/yield_expression.rs @@ -1,7 +1,7 @@ use swc_ecma_ast::YieldExpr; -use crate::{store_yield_expression, store_yield_expression_flags}; use crate::convert_ast::converter::AstConverter; +use crate::{store_yield_expression, store_yield_expression_flags}; impl<'a> AstConverter<'a> { pub(crate) fn store_yield_expression(&mut self, yield_expression: &YieldExpr) { diff --git a/rust/parse_ast/src/convert_ast/annotations.rs b/rust/parse_ast/src/convert_ast/annotations.rs index a624dc7902b..0ac6f31164a 100644 --- a/rust/parse_ast/src/convert_ast/annotations.rs +++ b/rust/parse_ast/src/convert_ast/annotations.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; -use swc_common::BytePos; use swc_common::comments::{Comment, Comments}; +use swc_common::BytePos; #[derive(Default)] pub(crate) struct SequentialComments { diff --git a/rust/parse_ast/src/convert_ast/converter.rs b/rust/parse_ast/src/convert_ast/converter.rs index 92f8a345a4a..c736feb1349 100644 --- a/rust/parse_ast/src/convert_ast/converter.rs +++ b/rust/parse_ast/src/convert_ast/converter.rs @@ -1,10 +1,10 @@ use swc_common::Span; use swc_ecma_ast::{ - AssignTarget, AssignTargetPat, Callee, CallExpr, ClassMember, Decl, ExportSpecifier, Expr, + AssignTarget, AssignTargetPat, CallExpr, Callee, ClassMember, Decl, ExportSpecifier, Expr, ExprOrSpread, ForHead, ImportSpecifier, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, - JSXElementChild, JSXElementName, JSXObject, Lit, ModuleDecl, ModuleExportName, - ModuleItem, NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, - PropOrSpread, SimpleAssignTarget, Stmt, VarDeclOrExpr, + JSXElementChild, JSXElementName, JSXObject, Lit, ModuleDecl, ModuleExportName, ModuleItem, + NamedExport, ObjectPatProp, OptChainBase, ParenExpr, Pat, Program, PropName, PropOrSpread, + SimpleAssignTarget, Stmt, VarDeclOrExpr, }; use crate::ast_nodes::call_expression::StoredCallee; diff --git a/rust/parse_ast/src/convert_ast/converter/utf16_positions.rs b/rust/parse_ast/src/convert_ast/converter/utf16_positions.rs index 22b7ba34587..7dccfe05e52 100644 --- a/rust/parse_ast/src/convert_ast/converter/utf16_positions.rs +++ b/rust/parse_ast/src/convert_ast/converter/utf16_positions.rs @@ -1,8 +1,8 @@ use std::slice::Iter; use std::str::Chars; -use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; use crate::convert_ast::annotations::CommentKind::Annotation; +use crate::convert_ast::annotations::{AnnotationKind, AnnotationWithType}; pub(crate) struct Utf8ToUtf16ByteIndexConverterAndAnnotationHandler<'a> { current_utf8_index: u32, diff --git a/rust/parse_ast/src/error_emit.rs b/rust/parse_ast/src/error_emit.rs index 3b78c80aa51..3a738704cd9 100644 --- a/rust/parse_ast/src/error_emit.rs +++ b/rust/parse_ast/src/error_emit.rs @@ -2,7 +2,7 @@ use std::{io::Write, mem::take, sync::Arc}; use anyhow::Error; use parking_lot::Mutex; -use swc_common::errors::{DiagnosticBuilder, Emitter, Handler, HANDLER, Level}; +use swc_common::errors::{DiagnosticBuilder, Emitter, Handler, Level, HANDLER}; use swc_ecma_ast::Program; use crate::ast_nodes::parse_error::get_parse_error_buffer; From 20074d51d0a43dedf6bb1825c58be4b3742fbf82 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Thu, 22 Aug 2024 18:52:06 +0200 Subject: [PATCH 43/62] Improve JSX rendering and move to parent element --- src/Module.ts | 16 +- src/ast/nodes/JSXAttribute.ts | 14 +- src/ast/nodes/JSXElement.ts | 309 +++++++++++++++++- src/ast/nodes/JSXFragment.ts | 91 +++++- src/ast/nodes/JSXOpeningElement.ts | 213 +----------- src/ast/nodes/JSXOpeningFragment.ts | 73 +---- src/ast/nodes/shared/JSXClosingBase.ts | 1 + src/ast/nodes/shared/JSXElementBase.ts | 39 +++ src/ast/nodes/shared/JSXOpeningBase.ts | 92 ------ src/utils/renderHelpers.ts | 3 +- .../_config.js | 1 + .../jsx/transpiles-react-jsx/_config.js | 1 + .../jsx/transpiles-react-jsx/_expected.js | 18 +- 13 files changed, 463 insertions(+), 408 deletions(-) create mode 100644 src/ast/nodes/shared/JSXElementBase.ts delete mode 100644 src/ast/nodes/shared/JSXOpeningBase.ts diff --git a/src/Module.ts b/src/Module.ts index 3b25c6d67ac..d8c7cddee09 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -40,7 +40,6 @@ import type { ModuleJSON, ModuleOptions, NormalizedInputOptions, - NormalizedJsxOptions, PartialNull, PreserveEntrySignaturesOption, ResolvedId, @@ -115,7 +114,7 @@ export interface AstContext { ) => void; addImport: (node: ImportDeclaration) => void; addImportMeta: (node: MetaProperty) => void; - addJsx: () => void; + addImportSource: (importSource: string) => void; code: string; deoptimizationTracker: PathTracker; error: (properties: RollupLog, pos: number) => never; @@ -873,7 +872,7 @@ export default class Module { addExport: this.addExport.bind(this), addImport: this.addImport.bind(this), addImportMeta: this.addImportMeta.bind(this), - addJsx: this.addJsx.bind(this), + addImportSource: this.addImportSource.bind(this), code, // Only needed for debugging deoptimizationTracker: this.graph.deoptimizationTracker, error: this.error.bind(this), @@ -1153,14 +1152,9 @@ export default class Module { } } - private addJsx(): void { - const jsx = this.options.jsx as NormalizedJsxOptions; - if (jsx.importSource && !this.sourcesWithAttributes.has(jsx.importSource)) { - this.sourcesWithAttributes.set(jsx.importSource, EMPTY_OBJECT); - } - // TODO Lukas is this needed? - if (jsx.mode === 'automatic' && !this.sourcesWithAttributes.has(jsx.jsxImportSource)) { - this.sourcesWithAttributes.set(jsx.jsxImportSource, EMPTY_OBJECT); + private addImportSource(importSource: string): void { + if (importSource && !this.sourcesWithAttributes.has(importSource)) { + this.sourcesWithAttributes.set(importSource, EMPTY_OBJECT); } } diff --git a/src/ast/nodes/JSXAttribute.ts b/src/ast/nodes/JSXAttribute.ts index c726e3b6a3e..0b2ab72b50c 100644 --- a/src/ast/nodes/JSXAttribute.ts +++ b/src/ast/nodes/JSXAttribute.ts @@ -1,7 +1,6 @@ import type MagicString from 'magic-string'; -import type { NormalizedJsxOptions } from '../../rollup/types'; import { stringifyObjectKeyIfNeeded } from '../../utils/identifierHelpers'; -import type { RenderOptions } from '../../utils/renderHelpers'; +import type { NodeRenderOptions, RenderOptions } from '../../utils/renderHelpers'; import type JSXElement from './JSXElement'; import type JSXExpressionContainer from './JSXExpressionContainer'; import type JSXFragment from './JSXFragment'; @@ -16,14 +15,17 @@ export default class JSXAttribute extends NodeBase { name!: JSXIdentifier | JSXNamespacedName; value!: Literal | JSXExpressionContainer | JSXElement | JSXFragment | null; - render(code: MagicString, options: RenderOptions): void { + render( + code: MagicString, + options: RenderOptions, + { jsxMode = 'preserve' }: NodeRenderOptions = {} + ): void { super.render(code, options); - const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (mode !== 'preserve') { + if (jsxMode !== 'preserve') { const { name, value } = this; const key = name instanceof JSXIdentifier ? name.name : `${name.namespace.name}:${name.name.name}`; - if (!(mode === 'automatic' && key === 'key')) { + if (!(jsxMode === 'automatic' && key === 'key')) { const safeKey = stringifyObjectKeyIfNeeded(key); if (key !== safeKey) { code.overwrite(name.start, name.end, safeKey, { contentOnly: true }); diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index c06de3ece64..fc91f9d6d21 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -1,29 +1,175 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../rollup/types'; +import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; +import type { InclusionContext } from '../ExecutionContext'; +import type Variable from '../variables/Variable'; +import type JSXAttribute from './JSXAttribute'; import type JSXClosingElement from './JSXClosingElement'; import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; import type JSXFragment from './JSXFragment'; import type JSXOpeningElement from './JSXOpeningElement'; +import JSXSpreadAttribute from './JSXSpreadAttribute'; import type JSXSpreadChild from './JSXSpreadChild'; import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; +import JSXElementBase from './shared/JSXElementBase'; +import type { IncludeChildren } from './shared/Node'; -export default class JSXElement extends NodeBase { +type JsxMode = + | { + mode: 'preserve' | 'classic'; + factory: string | null; + importSource: string | null; + } + | { mode: 'automatic'; factory: string; importSource: string }; + +export default class JSXElement extends JSXElementBase { type!: NodeType.tJSXElement; openingElement!: JSXOpeningElement; closingElement!: JSXClosingElement | null; children!: (JSXText | JSXExpressionContainer | JSXElement | JSXFragment | JSXSpreadChild)[]; + private factoryVariable: Variable | null = null; + private factory: string | null = null; + // TODO Lukas use improved type so that mode and the rest align + private declare jsxMode: JsxMode; + + // TODO Lukas add import source here + initialise() { + super.initialise(); + const { importSource } = (this.jsxMode = this.getRenderingMode()); + if (importSource) { + this.scope.context.addImportSource(importSource); + } + } + + include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) { + if (!this.included) { + const { factory, importSource, mode } = this.jsxMode; + if (importSource) { + this.scope.context.addImportSource(importSource); + } + if (factory) { + this.factory = factory; + this.factoryVariable = this.getAndIncludeFactoryVariable( + factory, + mode === 'preserve', + importSource + ); + } + } + super.include(context, includeChildrenRecursively); + } + render(code: MagicString, options: RenderOptions): void { - const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; - if (mode === 'preserve') { - super.render(code, options); + switch (this.jsxMode.mode) { + case 'classic': { + this.renderClassicMode(code, options); + break; + } + case 'automatic': { + this.renderAutomaticMode(code, options); + break; + } + default: { + super.render(code, options); + } + } + } + + private getRenderingMode(): JsxMode { + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + const { mode, factory, importSource } = jsx; + if (mode === 'automatic') { + // In the case there is a key after a spread attribute, we fall back to + // classic mode, see https://github.com/facebook/react/issues/20031#issuecomment-710346866 + // for reasoning. + let hasSpread = false; + for (const attribute of this.openingElement.attributes) { + if (attribute instanceof JSXSpreadAttribute) { + hasSpread = true; + } else if (hasSpread && attribute.name.name === 'key') { + return { factory, importSource, mode: 'classic' }; + } + } + return { + factory: getRenderedJsxChildren(this.children) > 1 ? 'jsxs' : 'jsx', + importSource: jsx.jsxImportSource, + mode + }; + } + return { factory, importSource, mode }; + } + + private renderClassicMode(code: MagicString, options: RenderOptions) { + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + // TODO Lukas extract more this values + const { + openingElement: { + attributes, + name: { start: nameStart, end: nameEnd }, + selfClosing, + end, + start + }, + factoryVariable + } = this; + const [, ...nestedName] = this.factory!.split('.'); + code.update( + start, + nameStart, + `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(` + ); + this.openingElement.render(code, options, { jsxMode: this.jsxMode.mode }); + if (attributes.some(attribute => attribute instanceof JSXSpreadAttribute)) { + if (attributes.length === 1) { + code.appendLeft(nameEnd, ','); + code.update(attributes[0].end, end, ''); + } else { + code.appendLeft(nameEnd, ', Object.assign('); + let inObject = false; + if (!(attributes[0] instanceof JSXSpreadAttribute)) { + code.appendLeft(nameEnd, '{'); + inObject = true; + } + for (let index = 1; index < attributes.length; index++) { + const attribute = attributes[index]; + if (attribute instanceof JSXSpreadAttribute) { + if (inObject) { + code.prependRight(attribute.start, '}, '); + inObject = false; + } else { + code.appendLeft(attributes[index - 1].end, ','); + } + } else if (inObject) { + code.appendLeft(attributes[index - 1].end, ','); + } else { + code.appendLeft(attributes[index - 1].end, ', {'); + inObject = true; + } + } + if (inObject) { + code.appendLeft(attributes.at(-1)!.end, ' }'); + } + code.update(attributes.at(-1)!.end, end, ')'); + } + } else if (attributes.length > 0) { + code.appendLeft(nameEnd, ', {'); + for (let index = 0; index < attributes.length - 1; index++) { + code.appendLeft(attributes[index].end, ', '); + } + code.update(attributes.at(-1)!.end, end, ' }'); + } else { + code.update(nameEnd, end, ', null'); + } + if (selfClosing) { + code.appendLeft(end, ')'); } else { - this.openingElement.render(code, options); - let prependComma = mode === 'classic'; for (const child of this.children) { if ( child instanceof JSXExpressionContainer && @@ -32,14 +178,153 @@ export default class JSXElement extends NodeBase { code.remove(child.start, child.end); } else { child.render(code, options); - if (prependComma) { - code.appendLeft(child.start, `, `); - } else { - prependComma = true; + code.appendLeft(child.start, `, `); + } + } + this.closingElement!.render(code); + } + } + + private renderAutomaticMode(code: MagicString, options: RenderOptions) { + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + // TODO Lukas extract more this values + const { + factoryVariable, + openingElement: { + attributes, + end, + start, + name: { start: nameStart, end: nameEnd }, + selfClosing + } + } = this; + code.update( + start, + nameStart, + `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(` + ); + this.openingElement.render(code, options, { jsxMode: this.jsxMode.mode }); + // TODO Lukas + // - render children first + // - if we have a spread and either regular attributes, a key attribute or children, then we need Object.assign + // - if we only have a single spread, we just print the object + // - otherwise we print a regular object + let keyAttribute: JSXAttribute | null = null; + let hasSpread = false; + let inObject = true; + let previousEnd = nameEnd; + let hasAttributes = false; + for (const attribute of attributes) { + if (attribute instanceof JSXSpreadAttribute) { + if (inObject) { + if (hasAttributes) { + code.appendLeft(previousEnd, ' '); + } + code.appendLeft(previousEnd, '},'); + inObject = false; + } else if (hasAttributes) { + code.appendLeft(previousEnd, ','); + } + previousEnd = attribute.end; + hasAttributes = true; + hasSpread = true; + } else if (attribute.name.name === 'key') { + keyAttribute = attribute; + code.remove(previousEnd, attribute.value?.start || attribute.end); + } else { + if (hasAttributes) { + code.appendLeft(previousEnd, ','); + } + if (!inObject) { + code.appendLeft(previousEnd, ' {'); + inObject = true; + } + previousEnd = attribute.end; + hasAttributes = true; + } + } + code.prependLeft(nameEnd, hasSpread ? ', Object.assign({' : ', {'); + const closeObjectAssign = hasSpread ? ')' : ''; + const renderedChildren = getRenderedJsxChildren(this.children); + let prependComma = false; + // TODO Lukas can we handle commas differently? + for (const child of this.children) { + if ( + child instanceof JSXExpressionContainer && + child.expression instanceof JSXEmptyExpression + ) { + code.remove(child.start, child.end); + } else { + child.render(code, options); + if (prependComma) { + code.appendLeft(child.start, `, `); + } else { + prependComma = true; + } + } + } + if (renderedChildren > 0) { + if (hasAttributes) { + code.appendLeft(previousEnd, ','); + } + if (!inObject) { + code.appendLeft(previousEnd, ' {'); + } + code.update( + attributes.at(-1)?.end || previousEnd, + end, + ` children: ${renderedChildren > 1 ? '[' : ''}` + ); + const childrenClose = renderedChildren > 1 ? ']' : ''; + if (keyAttribute) { + const { value } = keyAttribute; + if (value) { + code.prependRight(value.start, `${childrenClose} }${closeObjectAssign}, `); + code.move(value.start, value.end, this.closingElement!.start); + } else { + code.prependRight( + this.closingElement!.start, + `${childrenClose} }${closeObjectAssign}, true` + ); + } + } else { + // We need to attach to the right as children are not rendered yet and + // this appendLeft will not append to things appended by the children + code.prependRight(this.closingElement!.start, `${childrenClose} }${closeObjectAssign}`); + } + } else { + if (inObject) { + if (hasAttributes) { + code.appendLeft(previousEnd, ' '); + } + code.update(attributes.at(-1)?.end || previousEnd, end, '}' + closeObjectAssign); + } else { + code.update(previousEnd, end, ')'); + } + if (keyAttribute) { + const { value } = keyAttribute; + // This will appear to the left of the moved code... + code.appendLeft(end, ', '); + if (value) { + if (selfClosing) { + // ...and this will appear to the right + code.appendLeft(value.end, ')'); + } + code.move(value.start, value.end, end); + } else { + code.appendLeft(end, 'true'); + if (selfClosing) { + code.appendLeft(end, ')'); } } + } else if (selfClosing) { + code.appendLeft(end, ')'); } - this.closingElement?.render(code); } + // TODO Lukas inline removal? + this.closingElement?.render(code); } } diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index 38e644840c8..f0064320d6f 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -1,6 +1,9 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../rollup/types'; +import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; +import type { InclusionContext } from '../ExecutionContext'; +import type Variable from '../variables/Variable'; import type JSXClosingFragment from './JSXClosingFragment'; import type JSXElement from './JSXElement'; import JSXEmptyExpression from './JSXEmptyExpression'; @@ -9,20 +12,85 @@ import type JSXOpeningFragment from './JSXOpeningFragment'; import type JSXSpreadChild from './JSXSpreadChild'; import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; +import JSXElementBase from './shared/JSXElementBase'; +import { type IncludeChildren } from './shared/Node'; -export default class JSXFragment extends NodeBase { +export default class JSXFragment extends JSXElementBase { type!: NodeType.tJSXElement; openingFragment!: JSXOpeningFragment; children!: (JSXText | JSXExpressionContainer | JSXSpreadChild | JSXElement | JSXFragment)[]; closingFragment!: JSXClosingFragment; + private factory: string | null = null; + private fragment: string | null = null; + private factoryVariable: Variable | null = null; + private fragmentVariable: Variable | null = null; + + // TODO Lukas add import source here + initialise() { + super.initialise(); + } + + include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) { + if (!this.included) { + const { factory, fragment, importSource, mode } = this.getRenderingMode(); + if (importSource) { + this.scope.context.addImportSource(importSource); + } + const preserve = mode === 'preserve'; + if (factory) { + this.factory = factory; + this.factoryVariable = this.getAndIncludeFactoryVariable(factory, preserve, importSource); + } + if (fragment != null) { + this.fragment = fragment; + this.fragmentVariable = this.getAndIncludeFactoryVariable(fragment, preserve, importSource); + } + } + super.include(context, includeChildrenRecursively); + } + render(code: MagicString, options: RenderOptions): void { const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; if (mode === 'preserve') { super.render(code, options); } else { + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + const [, ...nestedFactory] = this.factory!.split('.'); + const [, ...nestedFragment] = this.fragment!.split('.'); + const factory = [ + this.factoryVariable!.getName(getPropertyAccess, useOriginalName), + ...nestedFactory + ].join('.'); + const fragment = [ + this.fragmentVariable!.getName(getPropertyAccess, useOriginalName), + ...nestedFragment + ].join('.'); + code.update( + this.openingFragment.start, + this.openingFragment.end, + `/*#__PURE__*/${factory}(${fragment}, ` + ); this.openingFragment.render(code, options); + if (mode === 'classic') { + code.appendLeft(this.openingFragment.end, 'null'); + } else { + code.appendLeft(this.openingFragment.end, '{'); + const renderedChildren = getRenderedJsxChildren(this.children); + if (renderedChildren > 0) { + code.appendLeft( + this.openingFragment.end, + ` children: ${renderedChildren > 1 ? '[' : ''}` + ); + } + code.prependRight( + this.closingFragment.start, + `${renderedChildren > 1 ? '] ' : renderedChildren > 0 ? ' ' : ''}}` + ); + } let prependComma = mode === 'classic'; for (const child of this.children) { if ( @@ -42,4 +110,23 @@ export default class JSXFragment extends NodeBase { this.closingFragment?.render(code); } } + + private getRenderingMode(): { + mode: 'preserve' | 'classic' | 'automatic'; + factory: string | null; + fragment: string | null; + importSource: string | null; + } { + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + const { mode, factory, importSource } = jsx; + if (mode === 'automatic') { + return { + factory: getRenderedJsxChildren(this.children) > 1 ? 'jsxs' : 'jsx', + fragment: 'Fragment', + importSource: jsx.jsxImportSource, + mode + }; + } + return { factory, fragment: jsx.fragment, importSource, mode }; + } } diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index 32660846d92..9681e571e4d 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -1,221 +1,26 @@ import type MagicString from 'magic-string'; -import type { NormalizedJsxClassicOptions, NormalizedJsxOptions } from '../../rollup/types'; -import { getRenderedJsxChildren } from '../../utils/jsx'; -import type { RenderOptions } from '../../utils/renderHelpers'; +import type { NodeRenderOptions, RenderOptions } from '../../utils/renderHelpers'; import type JSXAttribute from './JSXAttribute'; -import type JSXElement from './JSXElement'; import type JSXIdentifier from './JSXIdentifier'; import type JSXMemberExpression from './JSXMemberExpression'; import type JSXNamespacedName from './JSXNamespacedName'; -import JSXSpreadAttribute from './JSXSpreadAttribute'; +import type JSXSpreadAttribute from './JSXSpreadAttribute'; import type * as NodeType from './NodeType'; -import JSXOpeningBase from './shared/JSXOpeningBase'; +import { NodeBase } from './shared/Node'; -export default class JSXOpeningElement extends JSXOpeningBase { +export default class JSXOpeningElement extends NodeBase { type!: NodeType.tJSXOpeningElement; name!: JSXIdentifier | JSXMemberExpression | JSXNamespacedName; attributes!: (JSXAttribute | JSXSpreadAttribute)[]; selfClosing!: boolean; - render(code: MagicString, options: RenderOptions): void { - super.render(code, options); - const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - switch (jsx.mode) { - case 'classic': { - this.renderClassicMode(code, options, jsx); - break; - } - case 'automatic': { - this.renderAutomaticMode(code, options); - break; - } - } - } - - private renderClassicMode( + render( code: MagicString, options: RenderOptions, - { factory }: NormalizedJsxClassicOptions - ) { - const { - snippets: { getPropertyAccess }, - useOriginalName - } = options; - const { - attributes, - end, - factoryVariable, - name: { start: nameStart, end: nameEnd }, - selfClosing, - start - } = this; - const [, ...nestedName] = factory.split('.'); - code.update( - start, - nameStart, - `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(` - ); - if (attributes.some(attribute => attribute instanceof JSXSpreadAttribute)) { - if (attributes.length === 1) { - code.appendLeft(nameEnd, ','); - code.update(attributes[0].end, end, ''); - } else { - code.appendLeft(nameEnd, ', Object.assign('); - let inObject = false; - if (!(attributes[0] instanceof JSXSpreadAttribute)) { - code.appendLeft(nameEnd, '{'); - inObject = true; - } - for (let index = 1; index < attributes.length; index++) { - const attribute = attributes[index]; - if (attribute instanceof JSXSpreadAttribute) { - if (inObject) { - code.prependRight(attribute.start, '}, '); - inObject = false; - } else { - code.appendLeft(attributes[index - 1].end, ','); - } - } else { - if (inObject) { - code.appendLeft(attributes[index - 1].end, ','); - } else { - code.appendLeft(attributes[index - 1].end, ', {'); - inObject = true; - } - } - } - if (inObject) { - code.appendLeft(attributes.at(-1)!.end, ' }'); - } - code.update(attributes.at(-1)!.end, end, ')'); - } - } else if (attributes.length > 0) { - code.appendLeft(nameEnd, ', {'); - for (let index = 0; index < attributes.length - 1; index++) { - code.appendLeft(attributes[index].end, ', '); - } - code.update(attributes.at(-1)!.end, end, ' }'); - } else { - code.update(nameEnd, end, ', null'); - } - if (selfClosing) { - code.appendLeft(end, ')'); - } - } - - private renderAutomaticMode(code: MagicString, options: RenderOptions) { - const { - snippets: { getPropertyAccess }, - useOriginalName - } = options; - const { - attributes, - end, - factoryVariable, - name: { start: nameStart, end: nameEnd }, - selfClosing, - start - } = this; - code.update( - start, - nameStart, - `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(` - ); - let keyAttribute: JSXAttribute | null = null; - let hasSpread = false; - let inObject = true; - let previousEnd = nameEnd; - let hasAttributes = false; - for (const attribute of attributes) { - if (attribute instanceof JSXSpreadAttribute) { - if (inObject) { - if (hasAttributes) { - code.appendLeft(previousEnd, ' '); - } - code.appendLeft(previousEnd, '},'); - inObject = false; - } else if (hasAttributes) { - code.appendLeft(previousEnd, ','); - } - previousEnd = attribute.end; - hasAttributes = true; - hasSpread = true; - } else if (attribute.name.name === 'key') { - keyAttribute = attribute; - code.remove(previousEnd, attribute.value?.start || attribute.end); - } else { - if (hasAttributes) { - code.appendLeft(previousEnd, ','); - } - if (!inObject) { - code.appendLeft(previousEnd, ' {'); - inObject = true; - } - previousEnd = attribute.end; - hasAttributes = true; - } - } - code.prependLeft(nameEnd, hasSpread ? ', Object.assign({' : ', {'); - const closeObjectAssign = hasSpread ? ')' : ''; - const parent = this.parent as JSXElement; - const renderedChildren = getRenderedJsxChildren(parent.children); - if (renderedChildren > 0) { - if (hasAttributes) { - code.appendLeft(previousEnd, ','); - } - if (!inObject) { - code.appendLeft(previousEnd, ' {'); - } - code.update( - attributes.at(-1)?.end || previousEnd, - end, - ` children: ${renderedChildren > 1 ? '[' : ''}` - ); - const childrenClose = renderedChildren > 1 ? ']' : ''; - if (keyAttribute) { - const { value } = keyAttribute; - if (value) { - code.prependRight(value.start, `${childrenClose} }${closeObjectAssign}, `); - code.move(value.start, value.end, parent.closingElement!.start); - } else { - code.prependRight( - parent.closingElement!.start, - `${childrenClose} }${closeObjectAssign}, true` - ); - } - } else { - // We need to attach to the right as children are not rendered yet and - // this appendLeft will not append to things appended by the children - code.prependRight(parent.closingElement!.start, `${childrenClose} }${closeObjectAssign}`); - } - } else { - if (inObject) { - if (hasAttributes) { - code.appendLeft(previousEnd, ' '); - } - code.update(attributes.at(-1)?.end || previousEnd, end, '}' + closeObjectAssign); - } else { - code.update(previousEnd, end, ')'); - } - if (keyAttribute) { - const { value } = keyAttribute; - // This will appear to the left of the moved code... - code.appendLeft(end, ', '); - if (value) { - if (selfClosing) { - // ...and this will appear to the right - code.appendLeft(value.end, ')'); - } - code.move(value.start, value.end, end); - } else { - code.appendLeft(end, 'true'); - if (selfClosing) { - code.appendLeft(end, ')'); - } - } - } else if (selfClosing) { - code.appendLeft(end, ')'); - } + { jsxMode = 'preserve' }: NodeRenderOptions = {} + ): void { + for (const attribute of this.attributes) { + attribute.render(code, options, { jsxMode }); } } } diff --git a/src/ast/nodes/JSXOpeningFragment.ts b/src/ast/nodes/JSXOpeningFragment.ts index f7a56238095..c92161303c4 100644 --- a/src/ast/nodes/JSXOpeningFragment.ts +++ b/src/ast/nodes/JSXOpeningFragment.ts @@ -1,77 +1,8 @@ -import type MagicString from 'magic-string'; -import type { NormalizedJsxOptions } from '../../rollup/types'; -import { getRenderedJsxChildren } from '../../utils/jsx'; -import type { RenderOptions } from '../../utils/renderHelpers'; -import type { InclusionContext } from '../ExecutionContext'; -import type Variable from '../variables/Variable'; -import type JSXFragment from './JSXFragment'; import type * as NodeType from './NodeType'; -import type { InclusionOptions } from './shared/Expression'; -import JSXOpeningBase from './shared/JSXOpeningBase'; -import { type IncludeChildren } from './shared/Node'; +import { NodeBase } from './shared/Node'; -export default class JSXOpeningFragment extends JSXOpeningBase { +export default class JSXOpeningFragment extends NodeBase { type!: NodeType.tJSXOpeningElement; attributes!: never[]; selfClosing!: false; - - private fragmentVariable: Variable | null = null; - - include( - context: InclusionContext, - includeChildrenRecursively: IncludeChildren, - options?: InclusionOptions - ): void { - if (!this.included) { - const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - const [fragment, importSource] = - jsx.mode === 'automatic' - ? ['Fragment', jsx.jsxImportSource] - : [jsx.fragment, jsx.importSource]; - if (fragment != null) { - this.fragmentVariable = this.getAndIncludeFactoryVariable( - fragment, - jsx.mode === 'preserve', - importSource - ); - } - } - super.include(context, includeChildrenRecursively, options); - } - - render(code: MagicString, options: RenderOptions): void { - super.render(code, options); - const { - snippets: { getPropertyAccess }, - useOriginalName - } = options; - const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - if (jsx.mode !== 'preserve') { - const [, ...nestedFactory] = jsx.mode === 'classic' ? jsx.factory.split('.') : []; - const [, ...nestedFragment] = jsx.mode === 'classic' ? jsx.fragment.split('.') : []; - const factory = [ - this.factoryVariable!.getName(getPropertyAccess, useOriginalName), - ...nestedFactory - ].join('.'); - const fragment = [ - this.fragmentVariable!.getName(getPropertyAccess, useOriginalName), - ...nestedFragment - ].join('.'); - code.update(this.start, this.end, `/*#__PURE__*/${factory}(${fragment}, `); - if (jsx.mode === 'classic') { - code.appendLeft(this.end, 'null'); - } else { - code.appendLeft(this.end, '{'); - const parent = this.parent as JSXFragment; - const renderedChildren = getRenderedJsxChildren(parent.children); - if (renderedChildren > 0) { - code.appendLeft(this.end, ` children: ${renderedChildren > 1 ? '[' : ''}`); - } - code.prependRight( - parent.closingFragment.start, - `${renderedChildren > 1 ? '] ' : renderedChildren > 0 ? ' ' : ''}}` - ); - } - } - } } diff --git a/src/ast/nodes/shared/JSXClosingBase.ts b/src/ast/nodes/shared/JSXClosingBase.ts index abd1d247eca..a6242e362e9 100644 --- a/src/ast/nodes/shared/JSXClosingBase.ts +++ b/src/ast/nodes/shared/JSXClosingBase.ts @@ -2,6 +2,7 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../../rollup/types'; import { NodeBase } from './Node'; +// TODO Lukas get rid of this and move into JSXElement export default class JSXClosingBase extends NodeBase { render(code: MagicString): void { const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; diff --git a/src/ast/nodes/shared/JSXElementBase.ts b/src/ast/nodes/shared/JSXElementBase.ts new file mode 100644 index 00000000000..05b07527f2c --- /dev/null +++ b/src/ast/nodes/shared/JSXElementBase.ts @@ -0,0 +1,39 @@ +import LocalVariable from '../../variables/LocalVariable'; +import type Variable from '../../variables/Variable'; +import { NodeBase } from './Node'; + +export default class JSXElementBase extends NodeBase { + protected getAndIncludeFactoryVariable( + factory: string, + preserve: boolean, + importSource: string | null + ): Variable { + const [baseName, nestedName] = factory.split('.'); + let factoryVariable: Variable; + if (importSource) { + factoryVariable = this.scope.context.getImportedJsxFactoryVariable( + nestedName ? 'default' : baseName, + this.start, + importSource + ); + if (preserve) { + // This pretends we are accessing an included global variable of the same name + const globalVariable = this.scope.findGlobal(baseName); + globalVariable.include(); + // This excludes this variable from renaming + factoryVariable.globalName = baseName; + } + } else { + factoryVariable = this.scope.findGlobal(baseName); + } + this.scope.context.includeVariableInModule(factoryVariable); + if (factoryVariable instanceof LocalVariable) { + factoryVariable.consolidateInitializers(); + factoryVariable.addUsedPlace(this); + this.scope.context.requestTreeshakingPass(); + } + return factoryVariable; + } + + protected applyDeoptimizations() {} +} diff --git a/src/ast/nodes/shared/JSXOpeningBase.ts b/src/ast/nodes/shared/JSXOpeningBase.ts deleted file mode 100644 index a1bc4086ca8..00000000000 --- a/src/ast/nodes/shared/JSXOpeningBase.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { NormalizedJsxOptions } from '../../../rollup/types'; -import { getRenderedJsxChildren } from '../../../utils/jsx'; -import type { InclusionContext } from '../../ExecutionContext'; -import LocalVariable from '../../variables/LocalVariable'; -import type Variable from '../../variables/Variable'; -import type JSXAttribute from '../JSXAttribute'; -import type JSXElement from '../JSXElement'; -import type JSXFragment from '../JSXFragment'; -import JSXSpreadAttribute from '../JSXSpreadAttribute'; -import type { InclusionOptions } from './Expression'; -import { type IncludeChildren, NodeBase } from './Node'; - -export default class JSXOpeningBase extends NodeBase { - attributes!: (JSXAttribute | JSXSpreadAttribute)[]; - protected factoryVariable: Variable | null = null; - - include( - context: InclusionContext, - includeChildrenRecursively: IncludeChildren, - options?: InclusionOptions - ): void { - if (!this.deoptimized) this.applyDeoptimizations(); - if (!this.included) { - const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - const automaticFactory = jsx.mode === 'automatic' && this.getAutomaticJsxFactoryName(); - if (automaticFactory) { - this.factoryVariable = this.getAndIncludeFactoryVariable( - automaticFactory, - false, - jsx.jsxImportSource - ); - } else if (jsx.factory) { - this.factoryVariable = this.getAndIncludeFactoryVariable( - jsx.factory, - jsx.mode === 'preserve', - jsx.importSource - ); - } - } - super.include(context, includeChildrenRecursively, options); - } - - initialise(): void { - super.initialise(); - this.scope.context.addJsx(); - } - - protected getAndIncludeFactoryVariable( - factory: string, - preserve: boolean, - importSource: string | null - ): Variable { - const [baseName, nestedName] = factory.split('.'); - let factoryVariable: Variable; - if (importSource) { - factoryVariable = this.scope.context.getImportedJsxFactoryVariable( - nestedName ? 'default' : baseName, - this.start, - importSource - ); - if (preserve) { - // This pretends we are accessing an included global variable of the same name - const globalVariable = this.scope.findGlobal(baseName); - globalVariable.include(); - // This excludes this variable from renaming - factoryVariable.globalName = baseName; - } - } else { - factoryVariable = this.scope.findGlobal(baseName); - } - this.scope.context.includeVariableInModule(factoryVariable); - if (factoryVariable instanceof LocalVariable) { - factoryVariable.consolidateInitializers(); - factoryVariable.addUsedPlace(this); - this.scope.context.requestTreeshakingPass(); - } - return factoryVariable; - } - - private getAutomaticJsxFactoryName() { - let hasSpread = false; - for (const attribute of this.attributes) { - if (attribute instanceof JSXSpreadAttribute) { - hasSpread = true; - } else if (hasSpread && attribute.name.name === 'key') { - return null; - } - } - const parent = this.parent as JSXElement | JSXFragment; - return getRenderedJsxChildren(parent.children) > 1 ? 'jsxs' : 'jsx'; - } -} diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index e0b2c2fc1c3..28613d3dfbb 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -2,8 +2,8 @@ import type MagicString from 'magic-string'; import type { Node, StatementNode } from '../ast/nodes/shared/Node'; import type Variable from '../ast/variables/Variable'; import type { InternalModuleFormat } from '../rollup/types'; -import type { PluginDriver } from './PluginDriver'; import type { GenerateCodeSnippets } from './generateCodeSnippets'; +import type { PluginDriver } from './PluginDriver'; import { treeshakeNode } from './treeshakeNode'; export interface RenderOptions { @@ -23,6 +23,7 @@ export interface NodeRenderOptions { isCalleeOfRenderedParent?: boolean; isNoStatement?: boolean; isShorthandProperty?: boolean; + jsxMode?: 'preserve' | 'classic' | 'automatic'; preventASI?: boolean; /* Indicates if the direct parent of an element changed. Necessary for determining the "this" context of callees. */ diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js index edcac60d1e7..8301994aa10 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js @@ -1,4 +1,5 @@ module.exports = defineTest({ + solo: true, description: 'transpiles JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-react-jsx/_config.js b/test/form/samples/jsx/transpiles-react-jsx/_config.js index 16f207347a8..a144b877eb3 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_config.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_config.js @@ -1,4 +1,5 @@ module.exports = defineTest({ + solo: true, description: 'transpiles JSX for react', options: { external: ['react/jsx-runtime'], diff --git a/test/form/samples/jsx/transpiles-react-jsx/_expected.js b/test/form/samples/jsx/transpiles-react-jsx/_expected.js index b220c12cc49..f38f189c512 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_expected.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_expected.js @@ -1,4 +1,5 @@ -import { jsx, jsxs, Fragment, createElement } from 'react/jsx-runtime'; +import { jsx, Fragment, jsxs } from 'react/jsx-runtime'; +import react from 'react'; const Foo = () => {}; const obj = { key: '2' }; @@ -11,7 +12,7 @@ console.log(/*#__PURE__*/jsx(Foo, { x: "1" })); console.log(/*#__PURE__*/jsx(Foo, {}, true)); console.log(/*#__PURE__*/jsx(Foo, {}, "1")); console.log(/*#__PURE__*/jsx(Foo, {}, "1")); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj))); +console.log(/*#__PURE__*/jsx(Foo, obj)); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { x: "1" }))); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj), "1")); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj), true)); @@ -57,11 +58,10 @@ console.log(/*#__PURE__*/jsxs(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { console.log(/*#__PURE__*/jsxs(Fragment, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); // createElement -console.log(_createElement(Foo, Object.assign({}, obj, { key: "1" }))); -console.log(_createElement(Foo, Object.assign({}, obj, { key: true }))); -console.log(_createElement(Foo, Object.assign({}, obj, obj, { x: "1", key: "1", y: "1" }))); -console.log(_createElement(Foo, Object.assign({}, obj, obj, { x: "1", key: true, y: "1" }))); -console.log(_createElement(Foo, Object.assign({}, obj, { key: "1" }))); -console.log(_createElement(Foo, Object.assign({}, obj, { key: "1" }), - /*#__PURE__*/jsx(Foo, {}))); +console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, { key: "1" }))); +console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, { key: true }))); +console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, obj, { x: "1", key: "1", y: "1" }))); +console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, obj, { x: "1", key: true, y: "1" }))); +console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, { key: "1" }))); +console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, { key: "1" }), /*#__PURE__*/jsx(Foo, {}))); From 43aafdb0b1fbbb722c7a8f68cd9bce5da868bc9f Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 23 Aug 2024 06:48:27 +0200 Subject: [PATCH 44/62] Align classic attribute rendering with automatic --- src/ast/nodes/JSXElement.ts | 75 +++++++++++-------- src/ast/nodes/JSXOpeningElement.ts | 1 + .../jsx/transpiles-jsx-attributes/_config.js | 1 + .../transpiles-jsx-attributes/_expected.js | 10 +-- .../jsx/transpiles-jsx-closing/_config.js | 1 + .../_expected.js | 10 +-- 6 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index fc91f9d6d21..a04bce17ade 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -126,46 +126,57 @@ export default class JSXElement extends JSXElementBase { `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(` ); this.openingElement.render(code, options, { jsxMode: this.jsxMode.mode }); - if (attributes.some(attribute => attribute instanceof JSXSpreadAttribute)) { - if (attributes.length === 1) { - code.appendLeft(nameEnd, ','); - code.update(attributes[0].end, end, ''); + + let hasSpread = false; + let inObject = false; + let previousEnd = nameEnd; + let hasAttributes = false; + for (const attribute of attributes) { + if (attribute instanceof JSXSpreadAttribute) { + if (inObject) { + if (hasAttributes) { + code.appendLeft(previousEnd, ' '); + } + code.appendLeft(previousEnd, '},'); + inObject = false; + } else { + code.appendLeft(previousEnd, ','); + } + previousEnd = attribute.end; + hasSpread = true; } else { - code.appendLeft(nameEnd, ', Object.assign('); - let inObject = false; - if (!(attributes[0] instanceof JSXSpreadAttribute)) { - code.appendLeft(nameEnd, '{'); + code.appendLeft(previousEnd, ','); + if (!inObject) { + code.prependRight(attribute.start, '{ '); inObject = true; } - for (let index = 1; index < attributes.length; index++) { - const attribute = attributes[index]; - if (attribute instanceof JSXSpreadAttribute) { - if (inObject) { - code.prependRight(attribute.start, '}, '); - inObject = false; - } else { - code.appendLeft(attributes[index - 1].end, ','); - } - } else if (inObject) { - code.appendLeft(attributes[index - 1].end, ','); - } else { - code.appendLeft(attributes[index - 1].end, ', {'); - inObject = true; - } + previousEnd = attribute.end; + } + hasAttributes = true; + } + if (hasSpread) { + if (attributes.length > 1) { + const { start } = attributes[0]; + if (attributes[0] instanceof JSXSpreadAttribute) { + code.prependRight(start, '{}, '); } + code.prependRight(start, 'Object.assign('); if (inObject) { - code.appendLeft(attributes.at(-1)!.end, ' }'); + code.appendLeft(previousEnd, ' }'); } - code.update(attributes.at(-1)!.end, end, ')'); - } - } else if (attributes.length > 0) { - code.appendLeft(nameEnd, ', {'); - for (let index = 0; index < attributes.length - 1; index++) { - code.appendLeft(attributes[index].end, ', '); + code.update(previousEnd, this.openingElement.end, ')'); + } else { + code.update(previousEnd, this.openingElement.end, ''); } - code.update(attributes.at(-1)!.end, end, ' }'); } else { - code.update(nameEnd, end, ', null'); + if (hasAttributes) { + if (inObject) { + code.appendLeft(previousEnd, ' }'); + } + code.update(previousEnd, this.openingElement.end, ''); + } else { + code.update(previousEnd, this.openingElement.end, ', null'); + } } if (selfClosing) { code.appendLeft(end, ')'); diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index 9681e571e4d..789d8c3d7e1 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -19,6 +19,7 @@ export default class JSXOpeningElement extends NodeBase { options: RenderOptions, { jsxMode = 'preserve' }: NodeRenderOptions = {} ): void { + this.name.render(code, options); for (const attribute of this.attributes) { attribute.render(code, options, { jsxMode }); } diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js index 6eec3cae05e..2fd4e047609 100644 --- a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js @@ -1,4 +1,5 @@ module.exports = defineTest({ + solo: true, description: 'transpiles JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js b/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js index 00859a4c3cb..f058ee679e1 100644 --- a/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js +++ b/test/form/samples/jsx/transpiles-jsx-attributes/_expected.js @@ -12,11 +12,11 @@ const Foo = () => {}; const value = 'value 3'; console.log(Foo, value); -const result = /*#__PURE__*/react.createElement(Foo$1, { - bar: true, - "baz:foo": "string", - "quux-nix": value$1, - element: /*#__PURE__*/react.createElement(Foo$1, null), +const result = /*#__PURE__*/react.createElement(Foo$1, + { bar: true, + "baz:foo": "string", + "quux-nix": value$1, + element: /*#__PURE__*/react.createElement(Foo$1, null), fragment: /*#__PURE__*/react.createElement(react.Fragment, null) }); export { result }; diff --git a/test/form/samples/jsx/transpiles-jsx-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-closing/_config.js index 719ece5beb1..533cbcf1f3f 100644 --- a/test/form/samples/jsx/transpiles-jsx-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-closing/_config.js @@ -1,4 +1,5 @@ module.exports = defineTest({ + solo: true, description: 'transpiles JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_expected.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_expected.js index 8a83ba54142..4329ca93823 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_expected.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_expected.js @@ -11,11 +11,11 @@ console.log(obj); const Foo = () => {}; const result1 = /*#__PURE__*/react.createElement(Foo, obj$1); -const result2 = /*#__PURE__*/react.createElement(Foo, Object.assign( obj$1, { prop: true })); -const result3 = /*#__PURE__*/react.createElement(Foo, Object.assign({ - prop1: true, - prop2: true - }, obj$1, +const result2 = /*#__PURE__*/react.createElement(Foo, Object.assign({}, obj$1, { prop: true })); +const result3 = /*#__PURE__*/react.createElement(Foo, + Object.assign({ prop1: true, + prop2: true }, + obj$1, obj$1)); export { result1, result2, result3 }; From 88acff7c494cd2d60463c96b74d23db850469e8c Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 31 Aug 2024 07:16:51 +0200 Subject: [PATCH 45/62] Refine classic mode rendering to make extraction easier --- src/ast/nodes/JSXElement.ts | 60 ++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index a04bce17ade..2dd478c3c34 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -108,24 +108,27 @@ export default class JSXElement extends JSXElementBase { snippets: { getPropertyAccess }, useOriginalName } = options; - // TODO Lukas extract more this values const { + children, + end, + factory, + jsxMode: { mode }, openingElement: { attributes, name: { start: nameStart, end: nameEnd }, selfClosing, - end, - start + end: openingEnd, + start: openingStart }, factoryVariable } = this; - const [, ...nestedName] = this.factory!.split('.'); + const [, ...nestedName] = factory!.split('.'); code.update( - start, + openingStart, nameStart, `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(` ); - this.openingElement.render(code, options, { jsxMode: this.jsxMode.mode }); + this.openingElement.render(code, options, { jsxMode: mode }); let hasSpread = false; let inObject = false; @@ -151,47 +154,44 @@ export default class JSXElement extends JSXElementBase { inObject = true; } previousEnd = attribute.end; + hasAttributes = true; } - hasAttributes = true; + } + if (inObject) { + code.appendLeft(previousEnd, ' }'); } if (hasSpread) { - if (attributes.length > 1) { + if (hasAttributes) { const { start } = attributes[0]; if (attributes[0] instanceof JSXSpreadAttribute) { code.prependRight(start, '{}, '); } code.prependRight(start, 'Object.assign('); - if (inObject) { - code.appendLeft(previousEnd, ' }'); - } - code.update(previousEnd, this.openingElement.end, ')'); + code.update(previousEnd, openingEnd, ')'); } else { - code.update(previousEnd, this.openingElement.end, ''); + code.update(previousEnd, openingEnd, ''); } + } else if (hasAttributes) { + code.update(previousEnd, openingEnd, ''); } else { - if (hasAttributes) { - if (inObject) { - code.appendLeft(previousEnd, ' }'); - } - code.update(previousEnd, this.openingElement.end, ''); + code.update(previousEnd, openingEnd, ', null'); + } + previousEnd = openingEnd; + for (const child of children) { + if ( + child instanceof JSXExpressionContainer && + child.expression instanceof JSXEmptyExpression + ) { + code.remove(previousEnd, child.end); } else { - code.update(previousEnd, this.openingElement.end, ', null'); + code.appendLeft(previousEnd, `, `); + child.render(code, options); } + previousEnd = child.end; } if (selfClosing) { code.appendLeft(end, ')'); } else { - for (const child of this.children) { - if ( - child instanceof JSXExpressionContainer && - child.expression instanceof JSXEmptyExpression - ) { - code.remove(child.start, child.end); - } else { - child.render(code, options); - code.appendLeft(child.start, `, `); - } - } this.closingElement!.render(code); } } From e5bbe8d3360d6ad97bedf38ca40560c54acc8cbb Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 1 Sep 2024 09:05:15 +0200 Subject: [PATCH 46/62] Refine automatic mode rendering --- src/ast/nodes/JSXElement.ts | 205 +++++++++++------- .../jsx/transpiles-react-jsx/_expected.js | 4 +- 2 files changed, 132 insertions(+), 77 deletions(-) diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 2dd478c3c34..f4071e355c8 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -203,29 +203,26 @@ export default class JSXElement extends JSXElementBase { } = options; // TODO Lukas extract more this values const { + end, factoryVariable, openingElement: { attributes, - end, - start, + end: openingEnd, + start: openingStart, name: { start: nameStart, end: nameEnd }, selfClosing } } = this; code.update( - start, + openingStart, nameStart, `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(` ); this.openingElement.render(code, options, { jsxMode: this.jsxMode.mode }); - // TODO Lukas - // - render children first - // - if we have a spread and either regular attributes, a key attribute or children, then we need Object.assign - // - if we only have a single spread, we just print the object - // - otherwise we print a regular object let keyAttribute: JSXAttribute | null = null; let hasSpread = false; - let inObject = true; + let startsWithSpread = false; + let inObject = false; let previousEnd = nameEnd; let hasAttributes = false; for (const attribute of attributes) { @@ -236,32 +233,33 @@ export default class JSXElement extends JSXElementBase { } code.appendLeft(previousEnd, '},'); inObject = false; - } else if (hasAttributes) { + } else { code.appendLeft(previousEnd, ','); } previousEnd = attribute.end; - hasAttributes = true; + if (!hasAttributes) { + startsWithSpread = true; + } hasSpread = true; } else if (attribute.name.name === 'key') { keyAttribute = attribute; code.remove(previousEnd, attribute.value?.start || attribute.end); } else { - if (hasAttributes) { - code.appendLeft(previousEnd, ','); - } + // TODO Lukas this is also what should happen for children + code.appendLeft(previousEnd, ','); if (!inObject) { - code.appendLeft(previousEnd, ' {'); + code.prependRight(attribute.start, '{ '); inObject = true; } previousEnd = attribute.end; hasAttributes = true; } } - code.prependLeft(nameEnd, hasSpread ? ', Object.assign({' : ', {'); - const closeObjectAssign = hasSpread ? ')' : ''; - const renderedChildren = getRenderedJsxChildren(this.children); - let prependComma = false; - // TODO Lukas can we handle commas differently? + // TODO Lukas or code.remove? + code.update(attributes.at(-1)?.end || previousEnd, openingEnd, ''); + let hasChildren = false; + let hasMultipleChildren = false; + let childrenStart = 0; for (const child of this.children) { if ( child instanceof JSXExpressionContainer && @@ -270,72 +268,129 @@ export default class JSXElement extends JSXElementBase { code.remove(child.start, child.end); } else { child.render(code, options); - if (prependComma) { + if (hasChildren) { code.appendLeft(child.start, `, `); + hasMultipleChildren = true; } else { - prependComma = true; + hasChildren = true; + childrenStart = child.start; } } } - if (renderedChildren > 0) { - if (hasAttributes) { - code.appendLeft(previousEnd, ','); - } + // Wrap the children now and update previousEnd before continuing + if (hasChildren) { + code.appendLeft(previousEnd, ','); + code.prependRight(childrenStart, ` children: ${hasMultipleChildren ? '[' : ''}`); if (!inObject) { - code.appendLeft(previousEnd, ' {'); + code.prependRight(childrenStart, ' {'); + inObject = true; } - code.update( - attributes.at(-1)?.end || previousEnd, - end, - ` children: ${renderedChildren > 1 ? '[' : ''}` - ); - const childrenClose = renderedChildren > 1 ? ']' : ''; - if (keyAttribute) { - const { value } = keyAttribute; - if (value) { - code.prependRight(value.start, `${childrenClose} }${closeObjectAssign}, `); - code.move(value.start, value.end, this.closingElement!.start); - } else { - code.prependRight( - this.closingElement!.start, - `${childrenClose} }${closeObjectAssign}, true` - ); - } - } else { - // We need to attach to the right as children are not rendered yet and - // this appendLeft will not append to things appended by the children - code.prependRight(this.closingElement!.start, `${childrenClose} }${closeObjectAssign}`); + previousEnd = this.closingElement!.start; + if (hasMultipleChildren) { + code.appendLeft(previousEnd, ']'); } - } else { - if (inObject) { - if (hasAttributes) { - code.appendLeft(previousEnd, ' '); + } + // This is the outside wrapping + if (inObject) { + code.appendLeft(previousEnd, ' }'); + } + if (hasSpread) { + // This is the only case where we need Object.assign + if (hasAttributes || hasChildren) { + // TODO Lukas this should be the start of the first non-key-attriburte + const { start } = attributes[0]; + if (startsWithSpread) { + code.prependRight(start, '{}, '); } - code.update(attributes.at(-1)?.end || previousEnd, end, '}' + closeObjectAssign); - } else { - code.update(previousEnd, end, ')'); + code.prependRight(start, 'Object.assign('); + code.appendLeft(previousEnd, ')'); } - if (keyAttribute) { - const { value } = keyAttribute; - // This will appear to the left of the moved code... - code.appendLeft(end, ', '); - if (value) { - if (selfClosing) { - // ...and this will appear to the right - code.appendLeft(value.end, ')'); - } - code.move(value.start, value.end, end); - } else { - code.appendLeft(end, 'true'); - if (selfClosing) { - code.appendLeft(end, ')'); - } - } - } else if (selfClosing) { - code.appendLeft(end, ')'); + } else if (!(hasAttributes || hasChildren)) { + code.appendLeft(previousEnd, ', {}'); + } + + if (keyAttribute) { + const { value } = keyAttribute; + // This will appear to the left of the moved code... + code.appendLeft(previousEnd, ', '); + if (value) { + // if (selfClosing) { + // // ...and this will appear to the right + // code.appendLeft(value.end, ')'); + // } + code.move(value.start, value.end, previousEnd); + } else { + code.appendLeft(previousEnd, 'true'); + // if (selfClosing) { + // code.appendLeft(openingEnd, ')'); + // } } } - // TODO Lukas inline removal? - this.closingElement?.render(code); + + if (selfClosing) { + // Moving the key attribute will + code.appendLeft(keyAttribute?.value?.end || end, ')'); + } else { + this.closingElement!.render(code); + } + + // if (hasChildren) { + // if (hasAttributes) { + // code.appendLeft(previousEnd, ','); + // } + // if (!inObject) { + // code.appendLeft(previousEnd, ' {'); + // } + // code.update( + // attributes.at(-1)?.end || previousEnd, + // openingEnd, + // ` children: ${renderedChildren > 1 ? '[' : ''}` + // ); + // const childrenClose = renderedChildren > 1 ? ']' : ''; + // if (keyAttribute) { + // const { value } = keyAttribute; + // if (value) { + // code.prependRight(value.start, `${childrenClose} }${closeObjectAssign}, `); + // code.move(value.start, value.end, this.closingElement!.start); + // } else { + // code.prependRight( + // this.closingElement!.start, + // `${childrenClose} }${closeObjectAssign}, true` + // ); + // } + // } else { + // // We need to attach to the right as children are not rendered yet and + // // this appendLeft will not append to things appended by the children + // code.prependRight(this.closingElement!.start, `${childrenClose} }${closeObjectAssign}`); + // } + // } else { + // if (inObject) { + // if (hasAttributes) { + // code.appendLeft(previousEnd, ' '); + // } + // code.update(attributes.at(-1)?.end || previousEnd, openingEnd, '}' + closeObjectAssign); + // } else { + // code.update(previousEnd, openingEnd, ')'); + // } + // if (keyAttribute) { + // const { value } = keyAttribute; + // // This will appear to the left of the moved code... + // code.appendLeft(openingEnd, ', '); + // if (value) { + // if (selfClosing) { + // // ...and this will appear to the right + // code.appendLeft(value.end, ')'); + // } + // code.move(value.start, value.end, openingEnd); + // } else { + // code.appendLeft(openingEnd, 'true'); + // if (selfClosing) { + // code.appendLeft(openingEnd, ')'); + // } + // } + // } else if (selfClosing) { + // code.appendLeft(openingEnd, ')'); + // } + // } } } diff --git a/test/form/samples/jsx/transpiles-react-jsx/_expected.js b/test/form/samples/jsx/transpiles-react-jsx/_expected.js index f38f189c512..47b0dfa2c71 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_expected.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_expected.js @@ -14,8 +14,8 @@ console.log(/*#__PURE__*/jsx(Foo, {}, "1")); console.log(/*#__PURE__*/jsx(Foo, {}, "1")); console.log(/*#__PURE__*/jsx(Foo, obj)); console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { x: "1" }))); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj), "1")); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj), true)); +console.log(/*#__PURE__*/jsx(Foo, obj, "1")); +console.log(/*#__PURE__*/jsx(Foo, obj, true)); console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj))); console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj), "1")); console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj), true)); From 6f33fe178c053c23ca7190ef55beb24fb2e25a36 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 1 Sep 2024 20:15:48 +0200 Subject: [PATCH 47/62] Fix automatic rendering --- src/ast/nodes/JSXElement.ts | 179 ++++++------------ src/ast/nodes/shared/JSXClosingBase.ts | 1 - .../jsx/transpiles-react-jsx/_config.js | 2 +- 3 files changed, 59 insertions(+), 123 deletions(-) diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index f4071e355c8..574aa96f54a 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -4,7 +4,7 @@ import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; import type { InclusionContext } from '../ExecutionContext'; import type Variable from '../variables/Variable'; -import type JSXAttribute from './JSXAttribute'; +import JSXAttribute from './JSXAttribute'; import type JSXClosingElement from './JSXClosingElement'; import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; @@ -33,10 +33,8 @@ export default class JSXElement extends JSXElementBase { private factoryVariable: Variable | null = null; private factory: string | null = null; - // TODO Lukas use improved type so that mode and the rest align private declare jsxMode: JsxMode; - // TODO Lukas add import source here initialise() { super.initialise(); const { importSource } = (this.jsxMode = this.getRenderingMode()); @@ -110,6 +108,7 @@ export default class JSXElement extends JSXElementBase { } = options; const { children, + closingElement, end, factory, jsxMode: { mode }, @@ -134,8 +133,16 @@ export default class JSXElement extends JSXElementBase { let inObject = false; let previousEnd = nameEnd; let hasAttributes = false; + let firstAttribute: JSXAttribute | JSXSpreadAttribute | null = null; for (const attribute of attributes) { - if (attribute instanceof JSXSpreadAttribute) { + if (attribute instanceof JSXAttribute) { + code.appendLeft(previousEnd, ','); + if (!inObject) { + code.prependRight(attribute.start, '{ '); + inObject = true; + } + hasAttributes = true; + } else { if (inObject) { if (hasAttributes) { code.appendLeft(previousEnd, ' '); @@ -145,18 +152,15 @@ export default class JSXElement extends JSXElementBase { } else { code.appendLeft(previousEnd, ','); } - previousEnd = attribute.end; hasSpread = true; - } else { - code.appendLeft(previousEnd, ','); - if (!inObject) { - code.prependRight(attribute.start, '{ '); - inObject = true; - } - previousEnd = attribute.end; - hasAttributes = true; + } + previousEnd = attribute.end; + if (!firstAttribute) { + firstAttribute = attribute; } } + code.remove(attributes.at(-1)?.end || previousEnd, openingEnd); + if (inObject) { code.appendLeft(previousEnd, ' }'); } @@ -167,15 +171,12 @@ export default class JSXElement extends JSXElementBase { code.prependRight(start, '{}, '); } code.prependRight(start, 'Object.assign('); - code.update(previousEnd, openingEnd, ')'); - } else { - code.update(previousEnd, openingEnd, ''); + code.appendLeft(previousEnd, ')'); } - } else if (hasAttributes) { - code.update(previousEnd, openingEnd, ''); - } else { - code.update(previousEnd, openingEnd, ', null'); + } else if (!hasAttributes) { + code.appendLeft(previousEnd, ', null'); } + previousEnd = openingEnd; for (const child of children) { if ( @@ -184,15 +185,16 @@ export default class JSXElement extends JSXElementBase { ) { code.remove(previousEnd, child.end); } else { - code.appendLeft(previousEnd, `, `); + code.appendLeft(previousEnd, ', '); child.render(code, options); } previousEnd = child.end; } + if (selfClosing) { code.appendLeft(end, ')'); } else { - this.closingElement!.render(code); + closingElement!.render(code); } } @@ -201,10 +203,12 @@ export default class JSXElement extends JSXElementBase { snippets: { getPropertyAccess }, useOriginalName } = options; - // TODO Lukas extract more this values const { + children, + closingElement, end, factoryVariable, + jsxMode: { mode }, openingElement: { attributes, end: openingEnd, @@ -218,15 +222,27 @@ export default class JSXElement extends JSXElementBase { nameStart, `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(` ); - this.openingElement.render(code, options, { jsxMode: this.jsxMode.mode }); + this.openingElement.render(code, options, { jsxMode: mode }); let keyAttribute: JSXAttribute | null = null; let hasSpread = false; - let startsWithSpread = false; let inObject = false; let previousEnd = nameEnd; let hasAttributes = false; + let firstAttribute: JSXAttribute | JSXSpreadAttribute | null = null; for (const attribute of attributes) { - if (attribute instanceof JSXSpreadAttribute) { + if (attribute instanceof JSXAttribute) { + if (attribute.name.name === 'key') { + keyAttribute = attribute; + code.remove(previousEnd, attribute.value?.start || attribute.end); + continue; + } + code.appendLeft(previousEnd, ','); + if (!inObject) { + code.prependRight(attribute.start, '{ '); + inObject = true; + } + hasAttributes = true; + } else { if (inObject) { if (hasAttributes) { code.appendLeft(previousEnd, ' '); @@ -236,56 +252,44 @@ export default class JSXElement extends JSXElementBase { } else { code.appendLeft(previousEnd, ','); } - previousEnd = attribute.end; - if (!hasAttributes) { - startsWithSpread = true; - } hasSpread = true; - } else if (attribute.name.name === 'key') { - keyAttribute = attribute; - code.remove(previousEnd, attribute.value?.start || attribute.end); - } else { - // TODO Lukas this is also what should happen for children - code.appendLeft(previousEnd, ','); - if (!inObject) { - code.prependRight(attribute.start, '{ '); - inObject = true; - } - previousEnd = attribute.end; - hasAttributes = true; + } + previousEnd = attribute.end; + if (!firstAttribute) { + firstAttribute = attribute; } } - // TODO Lukas or code.remove? - code.update(attributes.at(-1)?.end || previousEnd, openingEnd, ''); + code.remove(attributes.at(-1)?.end || previousEnd, openingEnd); let hasChildren = false; let hasMultipleChildren = false; let childrenStart = 0; - for (const child of this.children) { + previousEnd = openingEnd; + for (const child of children) { if ( child instanceof JSXExpressionContainer && child.expression instanceof JSXEmptyExpression ) { - code.remove(child.start, child.end); + code.remove(previousEnd, child.end); } else { + code.appendLeft(previousEnd, ', '); child.render(code, options); if (hasChildren) { - code.appendLeft(child.start, `, `); hasMultipleChildren = true; } else { hasChildren = true; childrenStart = child.start; } } + previousEnd = child.end; } // Wrap the children now and update previousEnd before continuing if (hasChildren) { - code.appendLeft(previousEnd, ','); - code.prependRight(childrenStart, ` children: ${hasMultipleChildren ? '[' : ''}`); + code.prependRight(childrenStart, `children: ${hasMultipleChildren ? '[' : ''}`); if (!inObject) { - code.prependRight(childrenStart, ' {'); + code.prependRight(childrenStart, '{ '); inObject = true; } - previousEnd = this.closingElement!.start; + previousEnd = closingElement!.start; if (hasMultipleChildren) { code.appendLeft(previousEnd, ']'); } @@ -297,9 +301,8 @@ export default class JSXElement extends JSXElementBase { if (hasSpread) { // This is the only case where we need Object.assign if (hasAttributes || hasChildren) { - // TODO Lukas this should be the start of the first non-key-attriburte - const { start } = attributes[0]; - if (startsWithSpread) { + const start = firstAttribute?.start || childrenStart; + if (firstAttribute instanceof JSXSpreadAttribute) { code.prependRight(start, '{}, '); } code.prependRight(start, 'Object.assign('); @@ -314,16 +317,9 @@ export default class JSXElement extends JSXElementBase { // This will appear to the left of the moved code... code.appendLeft(previousEnd, ', '); if (value) { - // if (selfClosing) { - // // ...and this will appear to the right - // code.appendLeft(value.end, ')'); - // } code.move(value.start, value.end, previousEnd); } else { code.appendLeft(previousEnd, 'true'); - // if (selfClosing) { - // code.appendLeft(openingEnd, ')'); - // } } } @@ -331,66 +327,7 @@ export default class JSXElement extends JSXElementBase { // Moving the key attribute will code.appendLeft(keyAttribute?.value?.end || end, ')'); } else { - this.closingElement!.render(code); + closingElement!.render(code); } - - // if (hasChildren) { - // if (hasAttributes) { - // code.appendLeft(previousEnd, ','); - // } - // if (!inObject) { - // code.appendLeft(previousEnd, ' {'); - // } - // code.update( - // attributes.at(-1)?.end || previousEnd, - // openingEnd, - // ` children: ${renderedChildren > 1 ? '[' : ''}` - // ); - // const childrenClose = renderedChildren > 1 ? ']' : ''; - // if (keyAttribute) { - // const { value } = keyAttribute; - // if (value) { - // code.prependRight(value.start, `${childrenClose} }${closeObjectAssign}, `); - // code.move(value.start, value.end, this.closingElement!.start); - // } else { - // code.prependRight( - // this.closingElement!.start, - // `${childrenClose} }${closeObjectAssign}, true` - // ); - // } - // } else { - // // We need to attach to the right as children are not rendered yet and - // // this appendLeft will not append to things appended by the children - // code.prependRight(this.closingElement!.start, `${childrenClose} }${closeObjectAssign}`); - // } - // } else { - // if (inObject) { - // if (hasAttributes) { - // code.appendLeft(previousEnd, ' '); - // } - // code.update(attributes.at(-1)?.end || previousEnd, openingEnd, '}' + closeObjectAssign); - // } else { - // code.update(previousEnd, openingEnd, ')'); - // } - // if (keyAttribute) { - // const { value } = keyAttribute; - // // This will appear to the left of the moved code... - // code.appendLeft(openingEnd, ', '); - // if (value) { - // if (selfClosing) { - // // ...and this will appear to the right - // code.appendLeft(value.end, ')'); - // } - // code.move(value.start, value.end, openingEnd); - // } else { - // code.appendLeft(openingEnd, 'true'); - // if (selfClosing) { - // code.appendLeft(openingEnd, ')'); - // } - // } - // } else if (selfClosing) { - // code.appendLeft(openingEnd, ')'); - // } - // } } } diff --git a/src/ast/nodes/shared/JSXClosingBase.ts b/src/ast/nodes/shared/JSXClosingBase.ts index a6242e362e9..abd1d247eca 100644 --- a/src/ast/nodes/shared/JSXClosingBase.ts +++ b/src/ast/nodes/shared/JSXClosingBase.ts @@ -2,7 +2,6 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../../rollup/types'; import { NodeBase } from './Node'; -// TODO Lukas get rid of this and move into JSXElement export default class JSXClosingBase extends NodeBase { render(code: MagicString): void { const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; diff --git a/test/form/samples/jsx/transpiles-react-jsx/_config.js b/test/form/samples/jsx/transpiles-react-jsx/_config.js index a144b877eb3..e7413664d90 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_config.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_config.js @@ -2,7 +2,7 @@ module.exports = defineTest({ solo: true, description: 'transpiles JSX for react', options: { - external: ['react/jsx-runtime'], + external: ['react', 'react/jsx-runtime'], jsx: 'react-jsx' } }); From b9bfb43ff178bb67fe5b851cd0f1da9eaac16d0a Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 2 Sep 2024 06:58:07 +0200 Subject: [PATCH 48/62] Extract attribute rendering --- src/ast/nodes/JSXElement.ts | 174 ++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 99 deletions(-) diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 574aa96f54a..55b89af79d4 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -111,63 +111,24 @@ export default class JSXElement extends JSXElementBase { closingElement, end, factory, - jsxMode: { mode }, - openingElement: { - attributes, - name: { start: nameStart, end: nameEnd }, - selfClosing, - end: openingEnd, - start: openingStart - }, - factoryVariable + factoryVariable, + openingElement: { end: openingEnd, selfClosing } } = this; const [, ...nestedName] = factory!.split('.'); - code.update( - openingStart, - nameStart, - `/*#__PURE__*/${[factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.')}(` + let { firstAttribute, hasAttributes, hasSpread, inObject, previousEnd } = this.renderAttributes( + code, + options, + [factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.'), + false ); - this.openingElement.render(code, options, { jsxMode: mode }); - - let hasSpread = false; - let inObject = false; - let previousEnd = nameEnd; - let hasAttributes = false; - let firstAttribute: JSXAttribute | JSXSpreadAttribute | null = null; - for (const attribute of attributes) { - if (attribute instanceof JSXAttribute) { - code.appendLeft(previousEnd, ','); - if (!inObject) { - code.prependRight(attribute.start, '{ '); - inObject = true; - } - hasAttributes = true; - } else { - if (inObject) { - if (hasAttributes) { - code.appendLeft(previousEnd, ' '); - } - code.appendLeft(previousEnd, '},'); - inObject = false; - } else { - code.appendLeft(previousEnd, ','); - } - hasSpread = true; - } - previousEnd = attribute.end; - if (!firstAttribute) { - firstAttribute = attribute; - } - } - code.remove(attributes.at(-1)?.end || previousEnd, openingEnd); if (inObject) { code.appendLeft(previousEnd, ' }'); } if (hasSpread) { if (hasAttributes) { - const { start } = attributes[0]; - if (attributes[0] instanceof JSXSpreadAttribute) { + const { start } = firstAttribute!; + if (firstAttribute instanceof JSXSpreadAttribute) { code.prependRight(start, '{}, '); } code.prependRight(start, 'Object.assign('); @@ -208,58 +169,15 @@ export default class JSXElement extends JSXElementBase { closingElement, end, factoryVariable, - jsxMode: { mode }, - openingElement: { - attributes, - end: openingEnd, - start: openingStart, - name: { start: nameStart, end: nameEnd }, - selfClosing - } + openingElement: { end: openingEnd, selfClosing } } = this; - code.update( - openingStart, - nameStart, - `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(` - ); - this.openingElement.render(code, options, { jsxMode: mode }); - let keyAttribute: JSXAttribute | null = null; - let hasSpread = false; - let inObject = false; - let previousEnd = nameEnd; - let hasAttributes = false; - let firstAttribute: JSXAttribute | JSXSpreadAttribute | null = null; - for (const attribute of attributes) { - if (attribute instanceof JSXAttribute) { - if (attribute.name.name === 'key') { - keyAttribute = attribute; - code.remove(previousEnd, attribute.value?.start || attribute.end); - continue; - } - code.appendLeft(previousEnd, ','); - if (!inObject) { - code.prependRight(attribute.start, '{ '); - inObject = true; - } - hasAttributes = true; - } else { - if (inObject) { - if (hasAttributes) { - code.appendLeft(previousEnd, ' '); - } - code.appendLeft(previousEnd, '},'); - inObject = false; - } else { - code.appendLeft(previousEnd, ','); - } - hasSpread = true; - } - previousEnd = attribute.end; - if (!firstAttribute) { - firstAttribute = attribute; - } - } - code.remove(attributes.at(-1)?.end || previousEnd, openingEnd); + let { firstAttribute, hasAttributes, hasSpread, inObject, keyAttribute, previousEnd } = + this.renderAttributes( + code, + options, + factoryVariable!.getName(getPropertyAccess, useOriginalName), + true + ); let hasChildren = false; let hasMultipleChildren = false; let childrenStart = 0; @@ -330,4 +248,62 @@ export default class JSXElement extends JSXElementBase { closingElement!.render(code); } } + + private renderAttributes( + code: MagicString, + options: RenderOptions, + factoryName: string, + extractKeyAttribute: boolean + ) { + const { + jsxMode: { mode }, + openingElement + } = this; + const { + attributes, + end: openingEnd, + start: openingStart, + name: { start: nameStart, end: nameEnd } + } = openingElement; + code.update(openingStart, nameStart, `/*#__PURE__*/${factoryName}(`); + openingElement.render(code, options, { jsxMode: mode }); + let keyAttribute: JSXAttribute | null = null; + let hasSpread = false; + let inObject = false; + let previousEnd = nameEnd; + let hasAttributes = false; + let firstAttribute: JSXAttribute | JSXSpreadAttribute | null = null; + for (const attribute of attributes) { + if (attribute instanceof JSXAttribute) { + if (extractKeyAttribute && attribute.name.name === 'key') { + keyAttribute = attribute; + code.remove(previousEnd, attribute.value?.start || attribute.end); + continue; + } + code.appendLeft(previousEnd, ','); + if (!inObject) { + code.prependRight(attribute.start, '{ '); + inObject = true; + } + hasAttributes = true; + } else { + if (inObject) { + if (hasAttributes) { + code.appendLeft(previousEnd, ' '); + } + code.appendLeft(previousEnd, '},'); + inObject = false; + } else { + code.appendLeft(previousEnd, ','); + } + hasSpread = true; + } + previousEnd = attribute.end; + if (!firstAttribute) { + firstAttribute = attribute; + } + } + code.remove(attributes.at(-1)?.end || previousEnd, openingEnd); + return { firstAttribute, hasAttributes, hasSpread, inObject, keyAttribute, previousEnd }; + } } From dac38b03288ad020c9550f4a8f7f75320dadf0a4 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 2 Sep 2024 09:29:59 +0200 Subject: [PATCH 49/62] Extract shared functionality --- src/ast/nodes/JSXElement.ts | 186 ++++++++++++++++++++---------------- 1 file changed, 101 insertions(+), 85 deletions(-) diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 55b89af79d4..8feff1f518c 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -24,12 +24,13 @@ type JsxMode = importSource: string | null; } | { mode: 'automatic'; factory: string; importSource: string }; +type JsxChild = JSXText | JSXExpressionContainer | JSXElement | JSXFragment | JSXSpreadChild; export default class JSXElement extends JSXElementBase { type!: NodeType.tJSXElement; openingElement!: JSXOpeningElement; closingElement!: JSXClosingElement | null; - children!: (JSXText | JSXExpressionContainer | JSXElement | JSXFragment | JSXSpreadChild)[]; + children!: JsxChild[]; private factoryVariable: Variable | null = null; private factory: string | null = null; @@ -107,50 +108,32 @@ export default class JSXElement extends JSXElementBase { useOriginalName } = options; const { - children, closingElement, end, factory, factoryVariable, - openingElement: { end: openingEnd, selfClosing } + openingElement: { selfClosing } } = this; const [, ...nestedName] = factory!.split('.'); - let { firstAttribute, hasAttributes, hasSpread, inObject, previousEnd } = this.renderAttributes( + const { firstAttribute, hasAttributes, hasSpread, inObject, previousEnd } = + this.renderAttributes( + code, + options, + [factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.'), + false + ); + + this.wrapAttributes( code, - options, - [factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedName].join('.'), - false + inObject, + hasAttributes, + hasSpread, + firstAttribute, + 'null', + previousEnd ); - if (inObject) { - code.appendLeft(previousEnd, ' }'); - } - if (hasSpread) { - if (hasAttributes) { - const { start } = firstAttribute!; - if (firstAttribute instanceof JSXSpreadAttribute) { - code.prependRight(start, '{}, '); - } - code.prependRight(start, 'Object.assign('); - code.appendLeft(previousEnd, ')'); - } - } else if (!hasAttributes) { - code.appendLeft(previousEnd, ', null'); - } - - previousEnd = openingEnd; - for (const child of children) { - if ( - child instanceof JSXExpressionContainer && - child.expression instanceof JSXEmptyExpression - ) { - code.remove(previousEnd, child.end); - } else { - code.appendLeft(previousEnd, ', '); - child.render(code, options); - } - previousEnd = child.end; - } + this.renderChildren(code, options); if (selfClosing) { code.appendLeft(end, ')'); @@ -165,11 +148,10 @@ export default class JSXElement extends JSXElementBase { useOriginalName } = options; const { - children, closingElement, end, factoryVariable, - openingElement: { end: openingEnd, selfClosing } + openingElement: { selfClosing } } = this; let { firstAttribute, hasAttributes, hasSpread, inObject, keyAttribute, previousEnd } = this.renderAttributes( @@ -178,33 +160,13 @@ export default class JSXElement extends JSXElementBase { factoryVariable!.getName(getPropertyAccess, useOriginalName), true ); - let hasChildren = false; - let hasMultipleChildren = false; - let childrenStart = 0; - previousEnd = openingEnd; - for (const child of children) { - if ( - child instanceof JSXExpressionContainer && - child.expression instanceof JSXEmptyExpression - ) { - code.remove(previousEnd, child.end); - } else { - code.appendLeft(previousEnd, ', '); - child.render(code, options); - if (hasChildren) { - hasMultipleChildren = true; - } else { - hasChildren = true; - childrenStart = child.start; - } - } - previousEnd = child.end; - } - // Wrap the children now and update previousEnd before continuing - if (hasChildren) { - code.prependRight(childrenStart, `children: ${hasMultipleChildren ? '[' : ''}`); + + const { firstChild, hasMultipleChildren, childrenEnd } = this.renderChildren(code, options); + + if (firstChild) { + code.prependRight(firstChild.start, `children: ${hasMultipleChildren ? '[' : ''}`); if (!inObject) { - code.prependRight(childrenStart, '{ '); + code.prependRight(firstChild.start, '{ '); inObject = true; } previousEnd = closingElement!.start; @@ -212,32 +174,25 @@ export default class JSXElement extends JSXElementBase { code.appendLeft(previousEnd, ']'); } } - // This is the outside wrapping - if (inObject) { - code.appendLeft(previousEnd, ' }'); - } - if (hasSpread) { - // This is the only case where we need Object.assign - if (hasAttributes || hasChildren) { - const start = firstAttribute?.start || childrenStart; - if (firstAttribute instanceof JSXSpreadAttribute) { - code.prependRight(start, '{}, '); - } - code.prependRight(start, 'Object.assign('); - code.appendLeft(previousEnd, ')'); - } - } else if (!(hasAttributes || hasChildren)) { - code.appendLeft(previousEnd, ', {}'); - } + + this.wrapAttributes( + code, + inObject, + hasAttributes || !!firstChild, + hasSpread, + firstAttribute || firstChild, + '{}', + childrenEnd + ); if (keyAttribute) { const { value } = keyAttribute; // This will appear to the left of the moved code... - code.appendLeft(previousEnd, ', '); + code.appendLeft(childrenEnd, ', '); if (value) { - code.move(value.start, value.end, previousEnd); + code.move(value.start, value.end, childrenEnd); } else { - code.appendLeft(previousEnd, 'true'); + code.appendLeft(childrenEnd, 'true'); } } @@ -254,7 +209,14 @@ export default class JSXElement extends JSXElementBase { options: RenderOptions, factoryName: string, extractKeyAttribute: boolean - ) { + ): { + firstAttribute: JSXAttribute | JSXSpreadAttribute | JsxChild | null; + hasAttributes: boolean; + hasSpread: boolean; + inObject: boolean; + keyAttribute: JSXAttribute | null; + previousEnd: number; + } { const { jsxMode: { mode }, openingElement @@ -306,4 +268,58 @@ export default class JSXElement extends JSXElementBase { code.remove(attributes.at(-1)?.end || previousEnd, openingEnd); return { firstAttribute, hasAttributes, hasSpread, inObject, keyAttribute, previousEnd }; } + + private renderChildren(code: MagicString, options: RenderOptions) { + const { + children, + openingElement: { end: openingEnd } + } = this; + let hasMultipleChildren = false; + let childrenEnd = openingEnd; + let firstChild: JsxChild | null = null; + for (const child of children) { + if ( + child instanceof JSXExpressionContainer && + child.expression instanceof JSXEmptyExpression + ) { + code.remove(childrenEnd, child.end); + } else { + code.appendLeft(childrenEnd, ', '); + child.render(code, options); + if (firstChild) { + hasMultipleChildren = true; + } else { + firstChild = child; + } + } + childrenEnd = child.end; + } + return { childrenEnd, firstChild, hasMultipleChildren }; + } + + private wrapAttributes( + code: MagicString, + inObject: boolean, + hasAttributes: boolean, + hasSpread: boolean, + firstAttribute: JSXAttribute | JSXSpreadAttribute | JsxChild | null, + missingAttributesFallback: string, + attributesEnd: number + ) { + if (inObject) { + code.appendLeft(attributesEnd, ' }'); + } + if (hasSpread) { + if (hasAttributes) { + const { start } = firstAttribute!; + if (firstAttribute instanceof JSXSpreadAttribute) { + code.prependRight(start, '{}, '); + } + code.prependRight(start, 'Object.assign('); + code.appendLeft(attributesEnd, ')'); + } + } else if (!hasAttributes) { + code.appendLeft(attributesEnd, `, ${missingAttributesFallback}`); + } + } } From ed2ee433c6e63ac173a2b049ab023a5075779bc9 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 6 Sep 2024 10:49:16 +0200 Subject: [PATCH 50/62] Move initialize and include functionality to shared base element --- src/ast/nodes/JSXElement.ts | 35 +----- src/ast/nodes/JSXFragment.ts | 40 +++--- src/ast/nodes/shared/JSXElementBase.ts | 41 +++++- .../jsx/transpiles-empty-fragment/_config.js | 8 ++ .../transpiles-empty-fragment/_expected.js | 3 + .../jsx/transpiles-empty-fragment/main.js | 1 + .../jsx/transpiles-react-jsx/_expected.js | 117 ++++++++++-------- .../samples/jsx/transpiles-react-jsx/jsx.js | 15 +++ .../samples/jsx/transpiles-react-jsx/main.js | 66 +--------- .../jsx/transpiles-react-jsx/other1.js | 3 +- .../jsx/transpiles-react-jsx/other2.js | 3 +- 11 files changed, 158 insertions(+), 174 deletions(-) create mode 100644 test/form/samples/jsx/transpiles-empty-fragment/_config.js create mode 100644 test/form/samples/jsx/transpiles-empty-fragment/_expected.js create mode 100644 test/form/samples/jsx/transpiles-empty-fragment/main.js diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 8feff1f518c..1e69359eb3b 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -2,8 +2,6 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../rollup/types'; import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; -import type { InclusionContext } from '../ExecutionContext'; -import type Variable from '../variables/Variable'; import JSXAttribute from './JSXAttribute'; import type JSXClosingElement from './JSXClosingElement'; import JSXEmptyExpression from './JSXEmptyExpression'; @@ -15,7 +13,6 @@ import type JSXSpreadChild from './JSXSpreadChild'; import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; import JSXElementBase from './shared/JSXElementBase'; -import type { IncludeChildren } from './shared/Node'; type JsxMode = | { @@ -32,36 +29,6 @@ export default class JSXElement extends JSXElementBase { closingElement!: JSXClosingElement | null; children!: JsxChild[]; - private factoryVariable: Variable | null = null; - private factory: string | null = null; - private declare jsxMode: JsxMode; - - initialise() { - super.initialise(); - const { importSource } = (this.jsxMode = this.getRenderingMode()); - if (importSource) { - this.scope.context.addImportSource(importSource); - } - } - - include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) { - if (!this.included) { - const { factory, importSource, mode } = this.jsxMode; - if (importSource) { - this.scope.context.addImportSource(importSource); - } - if (factory) { - this.factory = factory; - this.factoryVariable = this.getAndIncludeFactoryVariable( - factory, - mode === 'preserve', - importSource - ); - } - } - super.include(context, includeChildrenRecursively); - } - render(code: MagicString, options: RenderOptions): void { switch (this.jsxMode.mode) { case 'classic': { @@ -78,7 +45,7 @@ export default class JSXElement extends JSXElementBase { } } - private getRenderingMode(): JsxMode { + protected getRenderingMode(): JsxMode { const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; const { mode, factory, importSource } = jsx; if (mode === 'automatic') { diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index f0064320d6f..b1dc30e9d0b 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -15,36 +15,43 @@ import type * as NodeType from './NodeType'; import JSXElementBase from './shared/JSXElementBase'; import { type IncludeChildren } from './shared/Node'; +type JsxModeWithFragment = + | { + mode: 'preserve' | 'classic'; + factory: string | null; + fragment: string | null; + importSource: string | null; + } + | { mode: 'automatic'; factory: string; fragment: string; importSource: string }; + export default class JSXFragment extends JSXElementBase { type!: NodeType.tJSXElement; openingFragment!: JSXOpeningFragment; children!: (JSXText | JSXExpressionContainer | JSXSpreadChild | JSXElement | JSXFragment)[]; closingFragment!: JSXClosingFragment; - private factory: string | null = null; private fragment: string | null = null; - private factoryVariable: Variable | null = null; private fragmentVariable: Variable | null = null; + protected declare jsxMode: JsxModeWithFragment; - // TODO Lukas add import source here initialise() { super.initialise(); + const { importSource } = (this.jsxMode = this.getRenderingMode()); + if (importSource) { + this.scope.context.addImportSource(importSource); + } } include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) { if (!this.included) { - const { factory, fragment, importSource, mode } = this.getRenderingMode(); - if (importSource) { - this.scope.context.addImportSource(importSource); - } - const preserve = mode === 'preserve'; - if (factory) { - this.factory = factory; - this.factoryVariable = this.getAndIncludeFactoryVariable(factory, preserve, importSource); - } + const { fragment, importSource, mode } = this.jsxMode; if (fragment != null) { this.fragment = fragment; - this.fragmentVariable = this.getAndIncludeFactoryVariable(fragment, preserve, importSource); + this.fragmentVariable = this.getAndIncludeFactoryVariable( + fragment, + mode === 'preserve', + importSource + ); } } super.include(context, includeChildrenRecursively); @@ -111,12 +118,7 @@ export default class JSXFragment extends JSXElementBase { } } - private getRenderingMode(): { - mode: 'preserve' | 'classic' | 'automatic'; - factory: string | null; - fragment: string | null; - importSource: string | null; - } { + protected getRenderingMode(): JsxModeWithFragment { const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; const { mode, factory, importSource } = jsx; if (mode === 'automatic') { diff --git a/src/ast/nodes/shared/JSXElementBase.ts b/src/ast/nodes/shared/JSXElementBase.ts index 05b07527f2c..986694e6a7c 100644 --- a/src/ast/nodes/shared/JSXElementBase.ts +++ b/src/ast/nodes/shared/JSXElementBase.ts @@ -1,8 +1,45 @@ +import type { InclusionContext } from '../../ExecutionContext'; import LocalVariable from '../../variables/LocalVariable'; import type Variable from '../../variables/Variable'; +import type { IncludeChildren } from './Node'; import { NodeBase } from './Node'; -export default class JSXElementBase extends NodeBase { +type JsxMode = + | { + mode: 'preserve' | 'classic'; + factory: string | null; + importSource: string | null; + } + | { mode: 'automatic'; factory: string; importSource: string }; + +export default abstract class JSXElementBase extends NodeBase { + protected factoryVariable: Variable | null = null; + protected factory: string | null = null; + protected declare jsxMode: JsxMode; + + initialise() { + super.initialise(); + const { importSource } = (this.jsxMode = this.getRenderingMode()); + if (importSource) { + this.scope.context.addImportSource(importSource); + } + } + + include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) { + if (!this.included) { + const { factory, importSource, mode } = this.jsxMode; + if (factory) { + this.factory = factory; + this.factoryVariable = this.getAndIncludeFactoryVariable( + factory, + mode === 'preserve', + importSource + ); + } + } + super.include(context, includeChildrenRecursively); + } + protected getAndIncludeFactoryVariable( factory: string, preserve: boolean, @@ -36,4 +73,6 @@ export default class JSXElementBase extends NodeBase { } protected applyDeoptimizations() {} + + protected abstract getRenderingMode(): JsxMode; } diff --git a/test/form/samples/jsx/transpiles-empty-fragment/_config.js b/test/form/samples/jsx/transpiles-empty-fragment/_config.js new file mode 100644 index 00000000000..e7413664d90 --- /dev/null +++ b/test/form/samples/jsx/transpiles-empty-fragment/_config.js @@ -0,0 +1,8 @@ +module.exports = defineTest({ + solo: true, + description: 'transpiles JSX for react', + options: { + external: ['react', 'react/jsx-runtime'], + jsx: 'react-jsx' + } +}); diff --git a/test/form/samples/jsx/transpiles-empty-fragment/_expected.js b/test/form/samples/jsx/transpiles-empty-fragment/_expected.js new file mode 100644 index 00000000000..fd1687b4abe --- /dev/null +++ b/test/form/samples/jsx/transpiles-empty-fragment/_expected.js @@ -0,0 +1,3 @@ +import { Fragment, jsx } from 'react/jsx-runtime'; + +console.log(/*#__PURE__*/jsx(Fragment, {})); diff --git a/test/form/samples/jsx/transpiles-empty-fragment/main.js b/test/form/samples/jsx/transpiles-empty-fragment/main.js new file mode 100644 index 00000000000..f6957f2d75b --- /dev/null +++ b/test/form/samples/jsx/transpiles-empty-fragment/main.js @@ -0,0 +1 @@ +console.log(<>); diff --git a/test/form/samples/jsx/transpiles-react-jsx/_expected.js b/test/form/samples/jsx/transpiles-react-jsx/_expected.js index 47b0dfa2c71..53b7d3dba63 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_expected.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_expected.js @@ -1,67 +1,78 @@ -import { jsx, Fragment, jsxs } from 'react/jsx-runtime'; +import { jsx as jsx$2, Fragment, jsxs as jsxs$2 } from 'react/jsx-runtime'; import react from 'react'; -const Foo = () => {}; -const obj = { key: '2' }; +const Foo$2 = 'wrong Foo 1'; +const obj$2 = 'wrong obj 1'; +const jsx$1 = 'wrong jsx 1'; +const jsxs$1 = 'wrong jsxs 1'; +console.log(Foo$2, obj$2, jsx$1, jsxs$1); + +const Foo$1 = () => {}; +const obj$1 = { key: '2' }; // jsx -console.log(/*#__PURE__*/jsx(Foo, {})); -console.log(/*#__PURE__*/jsx(Foo, { x: true })); -console.log(/*#__PURE__*/jsx(Foo, { x: "1" })); -console.log(/*#__PURE__*/jsx(Foo, { x: "1" })); -console.log(/*#__PURE__*/jsx(Foo, {}, true)); -console.log(/*#__PURE__*/jsx(Foo, {}, "1")); -console.log(/*#__PURE__*/jsx(Foo, {}, "1")); -console.log(/*#__PURE__*/jsx(Foo, obj)); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { x: "1" }))); -console.log(/*#__PURE__*/jsx(Foo, obj, "1")); -console.log(/*#__PURE__*/jsx(Foo, obj, true)); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj))); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj), "1")); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj), true)); +console.log(/*#__PURE__*/jsx$2(Foo$1, {})); +console.log(/*#__PURE__*/jsx$2(Foo$1, { x: true })); +console.log(/*#__PURE__*/jsx$2(Foo$1, { x: "1" })); +console.log(/*#__PURE__*/jsx$2(Foo$1, { x: "1" })); +console.log(/*#__PURE__*/jsx$2(Foo$1, {}, true)); +console.log(/*#__PURE__*/jsx$2(Foo$1, {}, "1")); +console.log(/*#__PURE__*/jsx$2(Foo$1, {}, "1")); +console.log(/*#__PURE__*/jsx$2(Foo$1, obj$1)); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({}, obj$1, { x: "1" }))); +console.log(/*#__PURE__*/jsx$2(Foo$1, obj$1, "1")); +console.log(/*#__PURE__*/jsx$2(Foo$1, obj$1, true)); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({ x: "1", y: "1" }, obj$1, obj$1))); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({ x: "1", y: "1" }, obj$1, obj$1), "1")); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({ x: "1", y: "1" }, obj$1, obj$1), true)); -console.log(/*#__PURE__*/jsx(Foo, {})); -console.log(/*#__PURE__*/jsx(Foo, { x: "1" })); -console.log(/*#__PURE__*/jsx(Foo, {}, "1")); -console.log(/*#__PURE__*/jsx(Foo, {}, true)); +console.log(/*#__PURE__*/jsx$2(Foo$1, {})); +console.log(/*#__PURE__*/jsx$2(Foo$1, { x: "1" })); +console.log(/*#__PURE__*/jsx$2(Foo$1, {}, "1")); +console.log(/*#__PURE__*/jsx$2(Foo$1, {}, true)); -console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) })); -console.log(/*#__PURE__*/jsx(Foo, { x: "1", children: /*#__PURE__*/jsx(Foo, {}) })); -console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) }, "1")); -console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) }, true)); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { children: /*#__PURE__*/jsx(Foo, {}) }))); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { x: "1", children: /*#__PURE__*/jsx(Foo, {}) }))); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), "1")); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({}, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), true)); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: /*#__PURE__*/jsx(Foo, {}) }))); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), "1")); -console.log(/*#__PURE__*/jsx(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: /*#__PURE__*/jsx(Foo, {}) }), true)); +console.log(/*#__PURE__*/jsx$2(Foo$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) })); +console.log(/*#__PURE__*/jsx$2(Foo$1, { x: "1", children: /*#__PURE__*/jsx$2(Foo$1, {}) })); +console.log(/*#__PURE__*/jsx$2(Foo$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) }, "1")); +console.log(/*#__PURE__*/jsx$2(Foo$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) }, true)); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({}, obj$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) }))); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({}, obj$1, { x: "1", children: /*#__PURE__*/jsx$2(Foo$1, {}) }))); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({}, obj$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) }), "1")); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({}, obj$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) }), true)); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({ x: "1", y: "1" }, obj$1, obj$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) }))); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({ x: "1", y: "1" }, obj$1, obj$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) }), "1")); +console.log(/*#__PURE__*/jsx$2(Foo$1, Object.assign({ x: "1", y: "1" }, obj$1, obj$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) }), true)); -console.log(/*#__PURE__*/jsx(Foo, { children: /*#__PURE__*/jsx(Foo, {}) })); +console.log(/*#__PURE__*/jsx$2(Foo$1, { children: /*#__PURE__*/jsx$2(Foo$1, {}) })); -console.log(/*#__PURE__*/jsx(Fragment, {})); -console.log(/*#__PURE__*/jsx(Fragment, { children: /*#__PURE__*/jsx(Foo, {}) })); +console.log(/*#__PURE__*/jsx$2(Fragment, {})); +console.log(/*#__PURE__*/jsx$2(Fragment, { children: /*#__PURE__*/jsx$2(Foo$1, {}) })); // jsxs -console.log(/*#__PURE__*/jsxs(Foo, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); -console.log(/*#__PURE__*/jsxs(Foo, { x: "1", children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); -console.log(/*#__PURE__*/jsxs(Foo, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }, "1")); -console.log(/*#__PURE__*/jsxs(Foo, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }, true)); -console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }))); -console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { x: "1", children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }))); -console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), "1")); -console.log(/*#__PURE__*/jsxs(Foo, Object.assign({}, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), true)); -console.log(/*#__PURE__*/jsxs(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }))); -console.log(/*#__PURE__*/jsxs(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), "1")); -console.log(/*#__PURE__*/jsxs(Foo, Object.assign({ x: "1", y: "1" }, obj, obj, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] }), true)); +console.log(/*#__PURE__*/jsxs$2(Foo$1, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] })); +console.log(/*#__PURE__*/jsxs$2(Foo$1, { x: "1", children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] })); +console.log(/*#__PURE__*/jsxs$2(Foo$1, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] }, "1")); +console.log(/*#__PURE__*/jsxs$2(Foo$1, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] }, true)); +console.log(/*#__PURE__*/jsxs$2(Foo$1, Object.assign({}, obj$1, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] }))); +console.log(/*#__PURE__*/jsxs$2(Foo$1, Object.assign({}, obj$1, { x: "1", children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] }))); +console.log(/*#__PURE__*/jsxs$2(Foo$1, Object.assign({}, obj$1, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] }), "1")); +console.log(/*#__PURE__*/jsxs$2(Foo$1, Object.assign({}, obj$1, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] }), true)); +console.log(/*#__PURE__*/jsxs$2(Foo$1, Object.assign({ x: "1", y: "1" }, obj$1, obj$1, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] }))); +console.log(/*#__PURE__*/jsxs$2(Foo$1, Object.assign({ x: "1", y: "1" }, obj$1, obj$1, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] }), "1")); +console.log(/*#__PURE__*/jsxs$2(Foo$1, Object.assign({ x: "1", y: "1" }, obj$1, obj$1, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] }), true)); -console.log(/*#__PURE__*/jsxs(Fragment, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); +console.log(/*#__PURE__*/jsxs$2(Fragment, { children: [/*#__PURE__*/jsx$2(Foo$1, {}), /*#__PURE__*/jsx$2(Foo$1, {})] })); // createElement -console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, { key: "1" }))); -console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, { key: true }))); -console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, obj, { x: "1", key: "1", y: "1" }))); -console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, obj, { x: "1", key: true, y: "1" }))); -console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, { key: "1" }))); -console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, { key: "1" }), /*#__PURE__*/jsx(Foo, {}))); +console.log(/*#__PURE__*/react.createElement(Foo$1, Object.assign({}, obj$1, { key: "1" }))); +console.log(/*#__PURE__*/react.createElement(Foo$1, Object.assign({}, obj$1, { key: true }))); +console.log(/*#__PURE__*/react.createElement(Foo$1, Object.assign({}, obj$1, obj$1, { x: "1", key: "1", y: "1" }))); +console.log(/*#__PURE__*/react.createElement(Foo$1, Object.assign({}, obj$1, obj$1, { x: "1", key: true, y: "1" }))); +console.log(/*#__PURE__*/react.createElement(Foo$1, Object.assign({}, obj$1, { key: "1" }))); +console.log(/*#__PURE__*/react.createElement(Foo$1, Object.assign({}, obj$1, { key: "1" }), /*#__PURE__*/jsx$2(Foo$1, {}))); +const Foo = 'wrong Foo 2'; +const obj = 'wrong obj 2'; +const jsx = 'wrong jsx 2'; +const jsxs = 'wrong jsxs 2'; +console.log(Foo, obj, jsx, jsxs); diff --git a/test/form/samples/jsx/transpiles-react-jsx/jsx.js b/test/form/samples/jsx/transpiles-react-jsx/jsx.js index 43ebc98b498..e3346bf6393 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/jsx.js +++ b/test/form/samples/jsx/transpiles-react-jsx/jsx.js @@ -3,26 +3,36 @@ const obj = { key: '2' }; // jsx console.log(); +console.log(); console.log(); +console.log(); +console.log(); console.log(); +console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); +console.log(); console.log({/* comment */}{/* comment */}); @@ -33,16 +43,21 @@ console.log(<>); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); console.log(); +console.log(); console.log(); console.log(); +console.log(); console.log(<>); // createElement console.log(); +console.log(); console.log(); +console.log(); console.log(); console.log(); diff --git a/test/form/samples/jsx/transpiles-react-jsx/main.js b/test/form/samples/jsx/transpiles-react-jsx/main.js index e3346bf6393..dfccae85926 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/main.js +++ b/test/form/samples/jsx/transpiles-react-jsx/main.js @@ -1,63 +1,3 @@ -const Foo = () => {}; -const obj = { key: '2' }; - -// jsx -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); - -console.log(); -console.log(); -console.log(); -console.log(); - -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); - -console.log({/* comment */}{/* comment */}); - -console.log(<>); -console.log(<>); - -// jsxs -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); - -console.log(<>); - -// createElement -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); -console.log(); +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/transpiles-react-jsx/other1.js b/test/form/samples/jsx/transpiles-react-jsx/other1.js index f99662c546c..9514c12c816 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/other1.js +++ b/test/form/samples/jsx/transpiles-react-jsx/other1.js @@ -2,5 +2,4 @@ const Foo = 'wrong Foo 1'; const obj = 'wrong obj 1'; const jsx = 'wrong jsx 1'; const jsxs = 'wrong jsxs 1'; -const createElement = 'wrong createElement 1'; -console.log(Foo, obj, jsx, jsxs, createElement); +console.log(Foo, obj, jsx, jsxs); diff --git a/test/form/samples/jsx/transpiles-react-jsx/other2.js b/test/form/samples/jsx/transpiles-react-jsx/other2.js index c87092e813a..802e2216e58 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/other2.js +++ b/test/form/samples/jsx/transpiles-react-jsx/other2.js @@ -2,5 +2,4 @@ const Foo = 'wrong Foo 2'; const obj = 'wrong obj 2'; const jsx = 'wrong jsx 2'; const jsxs = 'wrong jsxs 2'; -const createElement = 'wrong createElement 2'; -console.log(Foo, obj, jsx, jsxs, createElement); +console.log(Foo, obj, jsx, jsxs); From 59af083bf6168dd01d8f82a4d1e03a0fce2149ba Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 6 Sep 2024 11:53:22 +0200 Subject: [PATCH 51/62] Extract fragment opening rendering to JSXOpeningFragment --- src/ast/nodes/JSXElement.ts | 29 ++------ src/ast/nodes/JSXFragment.ts | 74 ++----------------- src/ast/nodes/JSXOpeningElement.ts | 5 +- src/ast/nodes/JSXOpeningFragment.ts | 54 +++++++++++++- src/ast/nodes/shared/JSXElementBase.ts | 65 ++++++---------- src/ast/nodes/shared/jsxHelpers.ts | 52 +++++++++++++ .../transpiles-empty-fragment/_expected.js | 2 +- 7 files changed, 142 insertions(+), 139 deletions(-) create mode 100644 src/ast/nodes/shared/jsxHelpers.ts diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 1e69359eb3b..d50444b8748 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -1,33 +1,21 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../rollup/types'; -import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; import JSXAttribute from './JSXAttribute'; import type JSXClosingElement from './JSXClosingElement'; import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; -import type JSXFragment from './JSXFragment'; import type JSXOpeningElement from './JSXOpeningElement'; import JSXSpreadAttribute from './JSXSpreadAttribute'; -import type JSXSpreadChild from './JSXSpreadChild'; -import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; import JSXElementBase from './shared/JSXElementBase'; - -type JsxMode = - | { - mode: 'preserve' | 'classic'; - factory: string | null; - importSource: string | null; - } - | { mode: 'automatic'; factory: string; importSource: string }; -type JsxChild = JSXText | JSXExpressionContainer | JSXElement | JSXFragment | JSXSpreadChild; +import type { JSXChild, JsxMode } from './shared/jsxHelpers'; export default class JSXElement extends JSXElementBase { type!: NodeType.tJSXElement; openingElement!: JSXOpeningElement; closingElement!: JSXClosingElement | null; - children!: JsxChild[]; + children!: JSXChild[]; render(code: MagicString, options: RenderOptions): void { switch (this.jsxMode.mode) { @@ -60,13 +48,8 @@ export default class JSXElement extends JSXElementBase { return { factory, importSource, mode: 'classic' }; } } - return { - factory: getRenderedJsxChildren(this.children) > 1 ? 'jsxs' : 'jsx', - importSource: jsx.jsxImportSource, - mode - }; } - return { factory, importSource, mode }; + return super.getRenderingMode(); } private renderClassicMode(code: MagicString, options: RenderOptions) { @@ -177,7 +160,7 @@ export default class JSXElement extends JSXElementBase { factoryName: string, extractKeyAttribute: boolean ): { - firstAttribute: JSXAttribute | JSXSpreadAttribute | JsxChild | null; + firstAttribute: JSXAttribute | JSXSpreadAttribute | JSXChild | null; hasAttributes: boolean; hasSpread: boolean; inObject: boolean; @@ -243,7 +226,7 @@ export default class JSXElement extends JSXElementBase { } = this; let hasMultipleChildren = false; let childrenEnd = openingEnd; - let firstChild: JsxChild | null = null; + let firstChild: JSXChild | null = null; for (const child of children) { if ( child instanceof JSXExpressionContainer && @@ -269,7 +252,7 @@ export default class JSXElement extends JSXElementBase { inObject: boolean, hasAttributes: boolean, hasSpread: boolean, - firstAttribute: JSXAttribute | JSXSpreadAttribute | JsxChild | null, + firstAttribute: JSXAttribute | JSXSpreadAttribute | JSXChild | null, missingAttributesFallback: string, attributesEnd: number ) { diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index b1dc30e9d0b..d109c0c1ce2 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -1,64 +1,22 @@ import type MagicString from 'magic-string'; -import type { NormalizedJsxOptions } from '../../rollup/types'; import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; -import type { InclusionContext } from '../ExecutionContext'; -import type Variable from '../variables/Variable'; import type JSXClosingFragment from './JSXClosingFragment'; -import type JSXElement from './JSXElement'; import JSXEmptyExpression from './JSXEmptyExpression'; import JSXExpressionContainer from './JSXExpressionContainer'; import type JSXOpeningFragment from './JSXOpeningFragment'; -import type JSXSpreadChild from './JSXSpreadChild'; -import type JSXText from './JSXText'; import type * as NodeType from './NodeType'; import JSXElementBase from './shared/JSXElementBase'; -import { type IncludeChildren } from './shared/Node'; - -type JsxModeWithFragment = - | { - mode: 'preserve' | 'classic'; - factory: string | null; - fragment: string | null; - importSource: string | null; - } - | { mode: 'automatic'; factory: string; fragment: string; importSource: string }; +import type { JSXChild } from './shared/jsxHelpers'; export default class JSXFragment extends JSXElementBase { type!: NodeType.tJSXElement; openingFragment!: JSXOpeningFragment; - children!: (JSXText | JSXExpressionContainer | JSXSpreadChild | JSXElement | JSXFragment)[]; + children!: JSXChild[]; closingFragment!: JSXClosingFragment; - private fragment: string | null = null; - private fragmentVariable: Variable | null = null; - protected declare jsxMode: JsxModeWithFragment; - - initialise() { - super.initialise(); - const { importSource } = (this.jsxMode = this.getRenderingMode()); - if (importSource) { - this.scope.context.addImportSource(importSource); - } - } - - include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) { - if (!this.included) { - const { fragment, importSource, mode } = this.jsxMode; - if (fragment != null) { - this.fragment = fragment; - this.fragmentVariable = this.getAndIncludeFactoryVariable( - fragment, - mode === 'preserve', - importSource - ); - } - } - super.include(context, includeChildrenRecursively); - } - render(code: MagicString, options: RenderOptions): void { - const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + const { mode } = this.jsxMode; if (mode === 'preserve') { super.render(code, options); } else { @@ -67,21 +25,13 @@ export default class JSXFragment extends JSXElementBase { useOriginalName } = options; const [, ...nestedFactory] = this.factory!.split('.'); - const [, ...nestedFragment] = this.fragment!.split('.'); const factory = [ this.factoryVariable!.getName(getPropertyAccess, useOriginalName), ...nestedFactory ].join('.'); - const fragment = [ - this.fragmentVariable!.getName(getPropertyAccess, useOriginalName), - ...nestedFragment - ].join('.'); - code.update( - this.openingFragment.start, - this.openingFragment.end, - `/*#__PURE__*/${factory}(${fragment}, ` - ); this.openingFragment.render(code, options); + code.prependRight(this.start, `/*#__PURE__*/${factory}(`); + code.appendLeft(this.openingFragment.end, ', '); if (mode === 'classic') { code.appendLeft(this.openingFragment.end, 'null'); } else { @@ -117,18 +67,4 @@ export default class JSXFragment extends JSXElementBase { this.closingFragment?.render(code); } } - - protected getRenderingMode(): JsxModeWithFragment { - const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; - const { mode, factory, importSource } = jsx; - if (mode === 'automatic') { - return { - factory: getRenderedJsxChildren(this.children) > 1 ? 'jsxs' : 'jsx', - fragment: 'Fragment', - importSource: jsx.jsxImportSource, - mode - }; - } - return { factory, fragment: jsx.fragment, importSource, mode }; - } } diff --git a/src/ast/nodes/JSXOpeningElement.ts b/src/ast/nodes/JSXOpeningElement.ts index 789d8c3d7e1..a7a57f06a72 100644 --- a/src/ast/nodes/JSXOpeningElement.ts +++ b/src/ast/nodes/JSXOpeningElement.ts @@ -1,4 +1,5 @@ import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; import type { NodeRenderOptions, RenderOptions } from '../../utils/renderHelpers'; import type JSXAttribute from './JSXAttribute'; import type JSXIdentifier from './JSXIdentifier'; @@ -17,7 +18,9 @@ export default class JSXOpeningElement extends NodeBase { render( code: MagicString, options: RenderOptions, - { jsxMode = 'preserve' }: NodeRenderOptions = {} + { + jsxMode = (this.scope.context.options.jsx as NormalizedJsxOptions).mode + }: NodeRenderOptions = {} ): void { this.name.render(code, options); for (const attribute of this.attributes) { diff --git a/src/ast/nodes/JSXOpeningFragment.ts b/src/ast/nodes/JSXOpeningFragment.ts index c92161303c4..6d50740c150 100644 --- a/src/ast/nodes/JSXOpeningFragment.ts +++ b/src/ast/nodes/JSXOpeningFragment.ts @@ -1,8 +1,60 @@ +import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; +import type { RenderOptions } from '../../utils/renderHelpers'; +import type { InclusionContext } from '../ExecutionContext'; +import type Variable from '../variables/Variable'; import type * as NodeType from './NodeType'; -import { NodeBase } from './shared/Node'; +import { getAndIncludeFactoryVariable } from './shared/jsxHelpers'; +import { type IncludeChildren, NodeBase } from './shared/Node'; export default class JSXOpeningFragment extends NodeBase { type!: NodeType.tJSXOpeningElement; attributes!: never[]; selfClosing!: false; + + private fragment: string | null = null; + private fragmentVariable: Variable | null = null; + + include(context: InclusionContext, includeChildrenRecursively: IncludeChildren) { + if (!this.included) { + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + if (jsx.mode === 'automatic') { + this.fragment = 'Fragment'; + this.fragmentVariable = getAndIncludeFactoryVariable( + 'Fragment', + false, + jsx.jsxImportSource, + this + ); + } else { + const { fragment, importSource, mode } = jsx; + if (fragment != null) { + this.fragment = fragment; + this.fragmentVariable = getAndIncludeFactoryVariable( + fragment, + mode === 'preserve', + importSource, + this + ); + } + } + } + super.include(context, includeChildrenRecursively); + } + + render(code: MagicString, options: RenderOptions): void { + const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; + if (mode !== 'preserve') { + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + const [, ...nestedFragment] = this.fragment!.split('.'); + const fragment = [ + this.fragmentVariable!.getName(getPropertyAccess, useOriginalName), + ...nestedFragment + ].join('.'); + code.update(this.start, this.end, fragment); + } + } } diff --git a/src/ast/nodes/shared/JSXElementBase.ts b/src/ast/nodes/shared/JSXElementBase.ts index 986694e6a7c..8e731ea2323 100644 --- a/src/ast/nodes/shared/JSXElementBase.ts +++ b/src/ast/nodes/shared/JSXElementBase.ts @@ -1,18 +1,15 @@ +import type { NormalizedJsxOptions } from '../../../rollup/types'; +import { getRenderedJsxChildren } from '../../../utils/jsx'; import type { InclusionContext } from '../../ExecutionContext'; -import LocalVariable from '../../variables/LocalVariable'; import type Variable from '../../variables/Variable'; +import type { JSXChild, JsxMode } from './jsxHelpers'; +import { getAndIncludeFactoryVariable } from './jsxHelpers'; import type { IncludeChildren } from './Node'; import { NodeBase } from './Node'; -type JsxMode = - | { - mode: 'preserve' | 'classic'; - factory: string | null; - importSource: string | null; - } - | { mode: 'automatic'; factory: string; importSource: string }; +export default class JSXElementBase extends NodeBase { + children!: JSXChild[]; -export default abstract class JSXElementBase extends NodeBase { protected factoryVariable: Variable | null = null; protected factory: string | null = null; protected declare jsxMode: JsxMode; @@ -30,49 +27,29 @@ export default abstract class JSXElementBase extends NodeBase { const { factory, importSource, mode } = this.jsxMode; if (factory) { this.factory = factory; - this.factoryVariable = this.getAndIncludeFactoryVariable( + this.factoryVariable = getAndIncludeFactoryVariable( factory, mode === 'preserve', - importSource + importSource, + this ); } } super.include(context, includeChildrenRecursively); } - protected getAndIncludeFactoryVariable( - factory: string, - preserve: boolean, - importSource: string | null - ): Variable { - const [baseName, nestedName] = factory.split('.'); - let factoryVariable: Variable; - if (importSource) { - factoryVariable = this.scope.context.getImportedJsxFactoryVariable( - nestedName ? 'default' : baseName, - this.start, - importSource - ); - if (preserve) { - // This pretends we are accessing an included global variable of the same name - const globalVariable = this.scope.findGlobal(baseName); - globalVariable.include(); - // This excludes this variable from renaming - factoryVariable.globalName = baseName; - } - } else { - factoryVariable = this.scope.findGlobal(baseName); - } - this.scope.context.includeVariableInModule(factoryVariable); - if (factoryVariable instanceof LocalVariable) { - factoryVariable.consolidateInitializers(); - factoryVariable.addUsedPlace(this); - this.scope.context.requestTreeshakingPass(); - } - return factoryVariable; - } - protected applyDeoptimizations() {} - protected abstract getRenderingMode(): JsxMode; + protected getRenderingMode(): JsxMode { + const jsx = this.scope.context.options.jsx as NormalizedJsxOptions; + const { mode, factory, importSource } = jsx; + if (mode === 'automatic') { + return { + factory: getRenderedJsxChildren(this.children) > 1 ? 'jsxs' : 'jsx', + importSource: jsx.jsxImportSource, + mode + }; + } + return { factory, importSource, mode }; + } } diff --git a/src/ast/nodes/shared/jsxHelpers.ts b/src/ast/nodes/shared/jsxHelpers.ts new file mode 100644 index 00000000000..bdbdfe8ef20 --- /dev/null +++ b/src/ast/nodes/shared/jsxHelpers.ts @@ -0,0 +1,52 @@ +import LocalVariable from '../../variables/LocalVariable'; +import type Variable from '../../variables/Variable'; +import type JSXElement from '../JSXElement'; +import type JSXExpressionContainer from '../JSXExpressionContainer'; +import type JSXFragment from '../JSXFragment'; +import type JSXOpeningElement from '../JSXOpeningElement'; +import type JSXOpeningFragment from '../JSXOpeningFragment'; +import type JSXSpreadChild from '../JSXSpreadChild'; +import type JSXText from '../JSXText'; +import type JSXElementBase from './JSXElementBase'; + +export type JsxMode = + | { + mode: 'preserve' | 'classic'; + factory: string | null; + importSource: string | null; + } + | { mode: 'automatic'; factory: string; importSource: string }; +export type JSXChild = JSXText | JSXExpressionContainer | JSXElement | JSXFragment | JSXSpreadChild; + +export function getAndIncludeFactoryVariable( + factory: string, + preserve: boolean, + importSource: string | null, + node: JSXElementBase | JSXOpeningElement | JSXOpeningFragment +): Variable { + const [baseName, nestedName] = factory.split('.'); + let factoryVariable: Variable; + if (importSource) { + factoryVariable = node.scope.context.getImportedJsxFactoryVariable( + nestedName ? 'default' : baseName, + node.start, + importSource + ); + if (preserve) { + // This pretends we are accessing an included global variable of the same name + const globalVariable = node.scope.findGlobal(baseName); + globalVariable.include(); + // This excludes this variable from renaming + factoryVariable.globalName = baseName; + } + } else { + factoryVariable = node.scope.findGlobal(baseName); + } + node.scope.context.includeVariableInModule(factoryVariable); + if (factoryVariable instanceof LocalVariable) { + factoryVariable.consolidateInitializers(); + factoryVariable.addUsedPlace(node); + node.scope.context.requestTreeshakingPass(); + } + return factoryVariable; +} diff --git a/test/form/samples/jsx/transpiles-empty-fragment/_expected.js b/test/form/samples/jsx/transpiles-empty-fragment/_expected.js index fd1687b4abe..5fd112f7f75 100644 --- a/test/form/samples/jsx/transpiles-empty-fragment/_expected.js +++ b/test/form/samples/jsx/transpiles-empty-fragment/_expected.js @@ -1,3 +1,3 @@ -import { Fragment, jsx } from 'react/jsx-runtime'; +import { jsx, Fragment } from 'react/jsx-runtime'; console.log(/*#__PURE__*/jsx(Fragment, {})); From b335d59a65bea3b451908dcf4c0dcb8566e72250 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 6 Sep 2024 12:28:36 +0200 Subject: [PATCH 52/62] Share rendering functionality with fragments --- src/ast/nodes/JSXElement.ts | 44 ++-------- src/ast/nodes/JSXFragment.ts | 113 ++++++++++++++----------- src/ast/nodes/shared/JSXElementBase.ts | 29 +++++++ 3 files changed, 101 insertions(+), 85 deletions(-) diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index d50444b8748..54a3674819b 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -3,8 +3,6 @@ import type { NormalizedJsxOptions } from '../../rollup/types'; import type { RenderOptions } from '../../utils/renderHelpers'; import JSXAttribute from './JSXAttribute'; import type JSXClosingElement from './JSXClosingElement'; -import JSXEmptyExpression from './JSXEmptyExpression'; -import JSXExpressionContainer from './JSXExpressionContainer'; import type JSXOpeningElement from './JSXOpeningElement'; import JSXSpreadAttribute from './JSXSpreadAttribute'; import type * as NodeType from './NodeType'; @@ -62,7 +60,7 @@ export default class JSXElement extends JSXElementBase { end, factory, factoryVariable, - openingElement: { selfClosing } + openingElement: { end: openingEnd, selfClosing } } = this; const [, ...nestedName] = factory!.split('.'); const { firstAttribute, hasAttributes, hasSpread, inObject, previousEnd } = @@ -83,7 +81,7 @@ export default class JSXElement extends JSXElementBase { previousEnd ); - this.renderChildren(code, options); + this.renderChildren(code, options, openingEnd); if (selfClosing) { code.appendLeft(end, ')'); @@ -101,7 +99,7 @@ export default class JSXElement extends JSXElementBase { closingElement, end, factoryVariable, - openingElement: { selfClosing } + openingElement: { end: openindEnd, selfClosing } } = this; let { firstAttribute, hasAttributes, hasSpread, inObject, keyAttribute, previousEnd } = this.renderAttributes( @@ -111,7 +109,11 @@ export default class JSXElement extends JSXElementBase { true ); - const { firstChild, hasMultipleChildren, childrenEnd } = this.renderChildren(code, options); + const { firstChild, hasMultipleChildren, childrenEnd } = this.renderChildren( + code, + options, + openindEnd + ); if (firstChild) { code.prependRight(firstChild.start, `children: ${hasMultipleChildren ? '[' : ''}`); @@ -147,7 +149,7 @@ export default class JSXElement extends JSXElementBase { } if (selfClosing) { - // Moving the key attribute will + // Moving the key attribute will also move the parenthesis to the right position code.appendLeft(keyAttribute?.value?.end || end, ')'); } else { closingElement!.render(code); @@ -219,34 +221,6 @@ export default class JSXElement extends JSXElementBase { return { firstAttribute, hasAttributes, hasSpread, inObject, keyAttribute, previousEnd }; } - private renderChildren(code: MagicString, options: RenderOptions) { - const { - children, - openingElement: { end: openingEnd } - } = this; - let hasMultipleChildren = false; - let childrenEnd = openingEnd; - let firstChild: JSXChild | null = null; - for (const child of children) { - if ( - child instanceof JSXExpressionContainer && - child.expression instanceof JSXEmptyExpression - ) { - code.remove(childrenEnd, child.end); - } else { - code.appendLeft(childrenEnd, ', '); - child.render(code, options); - if (firstChild) { - hasMultipleChildren = true; - } else { - firstChild = child; - } - } - childrenEnd = child.end; - } - return { childrenEnd, firstChild, hasMultipleChildren }; - } - private wrapAttributes( code: MagicString, inObject: boolean, diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index d109c0c1ce2..665818dfe91 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -1,9 +1,6 @@ import type MagicString from 'magic-string'; -import { getRenderedJsxChildren } from '../../utils/jsx'; import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXClosingFragment from './JSXClosingFragment'; -import JSXEmptyExpression from './JSXEmptyExpression'; -import JSXExpressionContainer from './JSXExpressionContainer'; import type JSXOpeningFragment from './JSXOpeningFragment'; import type * as NodeType from './NodeType'; import JSXElementBase from './shared/JSXElementBase'; @@ -16,55 +13,71 @@ export default class JSXFragment extends JSXElementBase { closingFragment!: JSXClosingFragment; render(code: MagicString, options: RenderOptions): void { - const { mode } = this.jsxMode; - if (mode === 'preserve') { - super.render(code, options); - } else { - const { - snippets: { getPropertyAccess }, - useOriginalName - } = options; - const [, ...nestedFactory] = this.factory!.split('.'); - const factory = [ - this.factoryVariable!.getName(getPropertyAccess, useOriginalName), - ...nestedFactory - ].join('.'); - this.openingFragment.render(code, options); - code.prependRight(this.start, `/*#__PURE__*/${factory}(`); - code.appendLeft(this.openingFragment.end, ', '); - if (mode === 'classic') { - code.appendLeft(this.openingFragment.end, 'null'); - } else { - code.appendLeft(this.openingFragment.end, '{'); - const renderedChildren = getRenderedJsxChildren(this.children); - if (renderedChildren > 0) { - code.appendLeft( - this.openingFragment.end, - ` children: ${renderedChildren > 1 ? '[' : ''}` - ); - } - code.prependRight( - this.closingFragment.start, - `${renderedChildren > 1 ? '] ' : renderedChildren > 0 ? ' ' : ''}}` - ); + switch (this.jsxMode.mode) { + case 'classic': { + this.renderClassicMode(code, options); + break; + } + case 'automatic': { + this.renderAutomaticMode(code, options); + break; } - let prependComma = mode === 'classic'; - for (const child of this.children) { - if ( - child instanceof JSXExpressionContainer && - child.expression instanceof JSXEmptyExpression - ) { - code.remove(child.start, child.end); - } else { - child.render(code, options); - if (prependComma) { - code.appendLeft(child.start, `, `); - } else { - prependComma = true; - } - } + default: { + super.render(code, options); + } + } + } + + private renderClassicMode(code: MagicString, options: RenderOptions) { + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + const { closingFragment, factory, factoryVariable, openingFragment, start } = this; + const [, ...nestedName] = factory!.split('.'); + openingFragment.render(code, options); + code.prependRight( + start, + `/*#__PURE__*/${[ + factoryVariable!.getName(getPropertyAccess, useOriginalName), + ...nestedName + ].join('.')}(` + ); + code.appendLeft(openingFragment.end, ', null'); + + this.renderChildren(code, options, openingFragment.end); + + closingFragment.render(code); + } + + private renderAutomaticMode(code: MagicString, options: RenderOptions) { + const { + snippets: { getPropertyAccess }, + useOriginalName + } = options; + const { closingFragment, factoryVariable, openingFragment, start } = this; + openingFragment.render(code, options); + code.prependRight( + start, + `/*#__PURE__*/${factoryVariable!.getName(getPropertyAccess, useOriginalName)}(` + ); + + const { firstChild, hasMultipleChildren, childrenEnd } = this.renderChildren( + code, + options, + openingFragment.end + ); + + if (firstChild) { + code.prependRight(firstChild.start, `{ children: ${hasMultipleChildren ? '[' : ''}`); + if (hasMultipleChildren) { + code.appendLeft(closingFragment.start, ']'); } - this.closingFragment?.render(code); + code.appendLeft(childrenEnd, ' }'); + } else { + code.appendLeft(openingFragment.end, ', {}'); } + + closingFragment.render(code); } } diff --git a/src/ast/nodes/shared/JSXElementBase.ts b/src/ast/nodes/shared/JSXElementBase.ts index 8e731ea2323..6f8b08e797d 100644 --- a/src/ast/nodes/shared/JSXElementBase.ts +++ b/src/ast/nodes/shared/JSXElementBase.ts @@ -1,7 +1,11 @@ +import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../../rollup/types'; import { getRenderedJsxChildren } from '../../../utils/jsx'; +import type { RenderOptions } from '../../../utils/renderHelpers'; import type { InclusionContext } from '../../ExecutionContext'; import type Variable from '../../variables/Variable'; +import JSXEmptyExpression from '../JSXEmptyExpression'; +import JSXExpressionContainer from '../JSXExpressionContainer'; import type { JSXChild, JsxMode } from './jsxHelpers'; import { getAndIncludeFactoryVariable } from './jsxHelpers'; import type { IncludeChildren } from './Node'; @@ -52,4 +56,29 @@ export default class JSXElementBase extends NodeBase { } return { factory, importSource, mode }; } + + protected renderChildren(code: MagicString, options: RenderOptions, openingEnd: number) { + const { children } = this; + let hasMultipleChildren = false; + let childrenEnd = openingEnd; + let firstChild: JSXChild | null = null; + for (const child of children) { + if ( + child instanceof JSXExpressionContainer && + child.expression instanceof JSXEmptyExpression + ) { + code.remove(childrenEnd, child.end); + } else { + code.appendLeft(childrenEnd, ', '); + child.render(code, options); + if (firstChild) { + hasMultipleChildren = true; + } else { + firstChild = child; + } + } + childrenEnd = child.end; + } + return { childrenEnd, firstChild, hasMultipleChildren }; + } } From 5ff072864e1d0dad9c693549de3106f8405f4d80 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 6 Sep 2024 12:45:01 +0200 Subject: [PATCH 53/62] Deconflict closing elements --- src/ast/nodes/JSXElement.ts | 4 ++-- src/ast/nodes/JSXFragment.ts | 4 ++-- src/ast/nodes/JSXIdentifier.ts | 3 ++- src/ast/nodes/shared/JSXClosingBase.ts | 5 ++++- test/form/samples/jsx/preserves-jsx-child/_config.js | 1 + test/form/samples/jsx/preserves-jsx-child/_expected.js | 10 +++++++--- test/form/samples/jsx/preserves-jsx-child/jsx.js | 2 ++ test/form/samples/jsx/preserves-jsx-child/main.js | 5 +++-- test/form/samples/jsx/preserves-jsx-child/other1.js | 2 ++ test/form/samples/jsx/preserves-jsx-child/other2.js | 2 ++ 10 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 test/form/samples/jsx/preserves-jsx-child/jsx.js create mode 100644 test/form/samples/jsx/preserves-jsx-child/other1.js create mode 100644 test/form/samples/jsx/preserves-jsx-child/other2.js diff --git a/src/ast/nodes/JSXElement.ts b/src/ast/nodes/JSXElement.ts index 54a3674819b..cd5ab4f449a 100644 --- a/src/ast/nodes/JSXElement.ts +++ b/src/ast/nodes/JSXElement.ts @@ -86,7 +86,7 @@ export default class JSXElement extends JSXElementBase { if (selfClosing) { code.appendLeft(end, ')'); } else { - closingElement!.render(code); + closingElement!.render(code, options); } } @@ -152,7 +152,7 @@ export default class JSXElement extends JSXElementBase { // Moving the key attribute will also move the parenthesis to the right position code.appendLeft(keyAttribute?.value?.end || end, ')'); } else { - closingElement!.render(code); + closingElement!.render(code, options); } } diff --git a/src/ast/nodes/JSXFragment.ts b/src/ast/nodes/JSXFragment.ts index 665818dfe91..a239459c866 100644 --- a/src/ast/nodes/JSXFragment.ts +++ b/src/ast/nodes/JSXFragment.ts @@ -47,7 +47,7 @@ export default class JSXFragment extends JSXElementBase { this.renderChildren(code, options, openingFragment.end); - closingFragment.render(code); + closingFragment.render(code, options); } private renderAutomaticMode(code: MagicString, options: RenderOptions) { @@ -78,6 +78,6 @@ export default class JSXFragment extends JSXElementBase { code.appendLeft(openingFragment.end, ', {}'); } - closingFragment.render(code); + closingFragment.render(code, options); } } diff --git a/src/ast/nodes/JSXIdentifier.ts b/src/ast/nodes/JSXIdentifier.ts index 868571d9656..d9d98e5936a 100644 --- a/src/ast/nodes/JSXIdentifier.ts +++ b/src/ast/nodes/JSXIdentifier.ts @@ -1,5 +1,6 @@ import type MagicString from 'magic-string'; import type { RenderOptions } from '../../utils/renderHelpers'; +import type JSXClosingElement from './JSXClosingElement'; import type JSXMemberExpression from './JSXMemberExpression'; import type JSXOpeningElement from './JSXOpeningElement'; import type * as NodeType from './NodeType'; @@ -36,7 +37,7 @@ export default class JSXIdentifier extends IdentifierBase { switch (this.parent.type) { case 'JSXOpeningElement': case 'JSXClosingElement': { - return (this.parent as JSXOpeningElement).name === this; + return (this.parent as JSXOpeningElement | JSXClosingElement).name === this; } case 'JSXMemberExpression': { return (this.parent as JSXMemberExpression).object === this; diff --git a/src/ast/nodes/shared/JSXClosingBase.ts b/src/ast/nodes/shared/JSXClosingBase.ts index abd1d247eca..9cb69e19bd7 100644 --- a/src/ast/nodes/shared/JSXClosingBase.ts +++ b/src/ast/nodes/shared/JSXClosingBase.ts @@ -1,12 +1,15 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../../rollup/types'; +import type { RenderOptions } from '../../../utils/renderHelpers'; import { NodeBase } from './Node'; export default class JSXClosingBase extends NodeBase { - render(code: MagicString): void { + render(code: MagicString, options: RenderOptions): void { const { mode } = this.scope.context.options.jsx as NormalizedJsxOptions; if (mode !== 'preserve') { code.overwrite(this.start, this.end, ')', { contentOnly: true }); + } else { + super.render(code, options); } } } diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js index 6eb31e3795c..ea00c851882 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -1,4 +1,5 @@ module.exports = defineTest({ + solo: true, description: 'preserves JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-jsx-child/_expected.js b/test/form/samples/jsx/preserves-jsx-child/_expected.js index 3897e5354e2..151374d5c7b 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_expected.js +++ b/test/form/samples/jsx/preserves-jsx-child/_expected.js @@ -1,4 +1,8 @@ -const Foo = () => {}; -const result = ; +const Foo$2 = 'wrong Foo 1'; +console.log(Foo$2); -export { result }; +const Foo$1 = () => {}; +console.log(); + +const Foo = 'wrong Foo 2'; +console.log(Foo); diff --git a/test/form/samples/jsx/preserves-jsx-child/jsx.js b/test/form/samples/jsx/preserves-jsx-child/jsx.js new file mode 100644 index 00000000000..ed02421e9af --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-child/jsx.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); diff --git a/test/form/samples/jsx/preserves-jsx-child/main.js b/test/form/samples/jsx/preserves-jsx-child/main.js index c863c74f668..dfccae85926 100644 --- a/test/form/samples/jsx/preserves-jsx-child/main.js +++ b/test/form/samples/jsx/preserves-jsx-child/main.js @@ -1,2 +1,3 @@ -const Foo = () => {}; -export const result = ; +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/preserves-jsx-child/other1.js b/test/form/samples/jsx/preserves-jsx-child/other1.js new file mode 100644 index 00000000000..297f5dfcc5b --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-child/other1.js @@ -0,0 +1,2 @@ +const Foo = 'wrong Foo 1'; +console.log(Foo); diff --git a/test/form/samples/jsx/preserves-jsx-child/other2.js b/test/form/samples/jsx/preserves-jsx-child/other2.js new file mode 100644 index 00000000000..e274d4042dd --- /dev/null +++ b/test/form/samples/jsx/preserves-jsx-child/other2.js @@ -0,0 +1,2 @@ +const Foo = 'wrong Foo 2'; +console.log(Foo); From a10024b7fd0838c5b259f8b05457e0777e34e417 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 9 Sep 2024 06:17:33 +0200 Subject: [PATCH 54/62] Handle native elements --- package-lock.json | 30 ----------------- src/ast/nodes/JSXIdentifier.ts | 33 ++++++++++++++++--- .../jsx/preserves-jsx-child/_config.js | 1 - .../jsx/preserves-native-elements/_config.js | 6 ++++ .../preserves-native-elements/_expected.js | 10 ++++++ .../jsx/preserves-native-elements/jsx.js | 5 +++ .../jsx/preserves-native-elements/main.js | 3 ++ .../jsx/preserves-native-elements/other1.js | 3 ++ .../jsx/preserves-native-elements/other2.js | 3 ++ .../jsx/transpiles-empty-fragment/_config.js | 1 - .../jsx/transpiles-jsx-attributes/_config.js | 1 - .../jsx/transpiles-jsx-closing/_config.js | 1 - .../_config.js | 1 - .../jsx/transpiles-native-elements/_config.js | 7 ++++ .../transpiles-native-elements/_expected.js | 12 +++++++ .../jsx/transpiles-native-elements/jsx.js | 5 +++ .../jsx/transpiles-native-elements/main.js | 3 ++ .../jsx/transpiles-native-elements/other1.js | 3 ++ .../jsx/transpiles-native-elements/other2.js | 3 ++ .../jsx/transpiles-react-jsx/_config.js | 1 - .../samples/jsx/missing-jsx-export/_config.js | 10 +++--- .../{react.js => react-jsx.js} | 0 22 files changed, 96 insertions(+), 46 deletions(-) create mode 100644 test/form/samples/jsx/preserves-native-elements/_config.js create mode 100644 test/form/samples/jsx/preserves-native-elements/_expected.js create mode 100644 test/form/samples/jsx/preserves-native-elements/jsx.js create mode 100644 test/form/samples/jsx/preserves-native-elements/main.js create mode 100644 test/form/samples/jsx/preserves-native-elements/other1.js create mode 100644 test/form/samples/jsx/preserves-native-elements/other2.js create mode 100644 test/form/samples/jsx/transpiles-native-elements/_config.js create mode 100644 test/form/samples/jsx/transpiles-native-elements/_expected.js create mode 100644 test/form/samples/jsx/transpiles-native-elements/jsx.js create mode 100644 test/form/samples/jsx/transpiles-native-elements/main.js create mode 100644 test/form/samples/jsx/transpiles-native-elements/other1.js create mode 100644 test/form/samples/jsx/transpiles-native-elements/other2.js rename test/function/samples/jsx/missing-jsx-export/{react.js => react-jsx.js} (100%) diff --git a/package-lock.json b/package-lock.json index 451166e7539..7cec3ec7b33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12104,36 +12104,6 @@ "rollup": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" } }, - "node_modules/rollup-plugin-license/node_modules/fdir": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.3.0.tgz", - "integrity": "sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/rollup-plugin-license/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/rollup-plugin-string": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/rollup-plugin-string/-/rollup-plugin-string-3.0.0.tgz", diff --git a/src/ast/nodes/JSXIdentifier.ts b/src/ast/nodes/JSXIdentifier.ts index d9d98e5936a..4cee922aa75 100644 --- a/src/ast/nodes/JSXIdentifier.ts +++ b/src/ast/nodes/JSXIdentifier.ts @@ -1,4 +1,5 @@ import type MagicString from 'magic-string'; +import type { NormalizedJsxOptions } from '../../rollup/types'; import type { RenderOptions } from '../../utils/renderHelpers'; import type JSXClosingElement from './JSXClosingElement'; import type JSXMemberExpression from './JSXMemberExpression'; @@ -6,14 +7,25 @@ import type JSXOpeningElement from './JSXOpeningElement'; import type * as NodeType from './NodeType'; import IdentifierBase from './shared/IdentifierBase'; +const enum IdentifierType { + Reference, + NativeElementName, + Other +} + export default class JSXIdentifier extends IdentifierBase { type!: NodeType.tJSXIdentifier; name!: string; + private isNativeElement = false; + bind(): void { - if (this.isReference()) { + const type = this.getType(); + if (type === IdentifierType.Reference) { this.variable = this.scope.findVariable(this.name); this.variable.addReference(this); + } else if (type === IdentifierType.NativeElementName) { + this.isNativeElement = true; } } @@ -30,21 +42,32 @@ export default class JSXIdentifier extends IdentifierBase { storeName: true }); } + } else if ( + this.isNativeElement && + (this.scope.context.options.jsx as NormalizedJsxOptions).mode !== 'preserve' + ) { + code.update(this.start, this.end, JSON.stringify(this.name)); } } - private isReference(): boolean { + private getType(): IdentifierType { switch (this.parent.type) { case 'JSXOpeningElement': case 'JSXClosingElement': { - return (this.parent as JSXOpeningElement | JSXClosingElement).name === this; + return (this.parent as JSXOpeningElement | JSXClosingElement).name === this + ? this.name.startsWith(this.name.charAt(0).toUpperCase()) + ? IdentifierType.Reference + : IdentifierType.NativeElementName + : IdentifierType.Other; } case 'JSXMemberExpression': { - return (this.parent as JSXMemberExpression).object === this; + return (this.parent as JSXMemberExpression).object === this + ? IdentifierType.Reference + : IdentifierType.Other; } case 'JSXAttribute': case 'JSXNamespacedName': { - return false; + return IdentifierType.Other; } default: { throw new Error(`Unexpected parent node type for JSXIdentifier: ${this.parent.type}`); diff --git a/test/form/samples/jsx/preserves-jsx-child/_config.js b/test/form/samples/jsx/preserves-jsx-child/_config.js index ea00c851882..6eb31e3795c 100644 --- a/test/form/samples/jsx/preserves-jsx-child/_config.js +++ b/test/form/samples/jsx/preserves-jsx-child/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - solo: true, description: 'preserves JSX children', options: { external: ['react'], diff --git a/test/form/samples/jsx/preserves-native-elements/_config.js b/test/form/samples/jsx/preserves-native-elements/_config.js new file mode 100644 index 00000000000..d64ae8ee707 --- /dev/null +++ b/test/form/samples/jsx/preserves-native-elements/_config.js @@ -0,0 +1,6 @@ +module.exports = defineTest({ + description: 'preserves native JSX elements', + options: { + jsx: 'preserve' + } +}); diff --git a/test/form/samples/jsx/preserves-native-elements/_expected.js b/test/form/samples/jsx/preserves-native-elements/_expected.js new file mode 100644 index 00000000000..c0427dd888e --- /dev/null +++ b/test/form/samples/jsx/preserves-native-elements/_expected.js @@ -0,0 +1,10 @@ +const div$1 = 'wrong div 1'; +const span$1 = 'wrong span 1'; +console.log(div$1, span$1); + +console.log(
); +console.log(
); + +const div = 'wrong div 2'; +const span = 'wrong span 2'; +console.log(div, span); diff --git a/test/form/samples/jsx/preserves-native-elements/jsx.js b/test/form/samples/jsx/preserves-native-elements/jsx.js new file mode 100644 index 00000000000..02159671af3 --- /dev/null +++ b/test/form/samples/jsx/preserves-native-elements/jsx.js @@ -0,0 +1,5 @@ +const div = 'wrong div'; +const span = 'wrong span'; + +console.log(
); +console.log(
); diff --git a/test/form/samples/jsx/preserves-native-elements/main.js b/test/form/samples/jsx/preserves-native-elements/main.js new file mode 100644 index 00000000000..dfccae85926 --- /dev/null +++ b/test/form/samples/jsx/preserves-native-elements/main.js @@ -0,0 +1,3 @@ +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/preserves-native-elements/other1.js b/test/form/samples/jsx/preserves-native-elements/other1.js new file mode 100644 index 00000000000..d607c512add --- /dev/null +++ b/test/form/samples/jsx/preserves-native-elements/other1.js @@ -0,0 +1,3 @@ +const div = 'wrong div 1'; +const span = 'wrong span 1'; +console.log(div, span); diff --git a/test/form/samples/jsx/preserves-native-elements/other2.js b/test/form/samples/jsx/preserves-native-elements/other2.js new file mode 100644 index 00000000000..25f1a5e7ad7 --- /dev/null +++ b/test/form/samples/jsx/preserves-native-elements/other2.js @@ -0,0 +1,3 @@ +const div = 'wrong div 2'; +const span = 'wrong span 2'; +console.log(div, span); diff --git a/test/form/samples/jsx/transpiles-empty-fragment/_config.js b/test/form/samples/jsx/transpiles-empty-fragment/_config.js index e7413664d90..d9c8a8452c7 100644 --- a/test/form/samples/jsx/transpiles-empty-fragment/_config.js +++ b/test/form/samples/jsx/transpiles-empty-fragment/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - solo: true, description: 'transpiles JSX for react', options: { external: ['react', 'react/jsx-runtime'], diff --git a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js index 2fd4e047609..6eec3cae05e 100644 --- a/test/form/samples/jsx/transpiles-jsx-attributes/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-attributes/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - solo: true, description: 'transpiles JSX with string attributes output', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-closing/_config.js b/test/form/samples/jsx/transpiles-jsx-closing/_config.js index 533cbcf1f3f..719ece5beb1 100644 --- a/test/form/samples/jsx/transpiles-jsx-closing/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-closing/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - solo: true, description: 'transpiles JSX closing element', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js index 8301994aa10..edcac60d1e7 100644 --- a/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js +++ b/test/form/samples/jsx/transpiles-jsx-spread-attribute/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - solo: true, description: 'transpiles JSX spread attributes', options: { external: ['react'], diff --git a/test/form/samples/jsx/transpiles-native-elements/_config.js b/test/form/samples/jsx/transpiles-native-elements/_config.js new file mode 100644 index 00000000000..52b1628b576 --- /dev/null +++ b/test/form/samples/jsx/transpiles-native-elements/_config.js @@ -0,0 +1,7 @@ +module.exports = defineTest({ + description: 'preserves native JSX elements', + options: { + external: ['react'], + jsx: 'react' + } +}); diff --git a/test/form/samples/jsx/transpiles-native-elements/_expected.js b/test/form/samples/jsx/transpiles-native-elements/_expected.js new file mode 100644 index 00000000000..fa825355679 --- /dev/null +++ b/test/form/samples/jsx/transpiles-native-elements/_expected.js @@ -0,0 +1,12 @@ +import react from 'react'; + +const div$1 = 'wrong div 1'; +const span$1 = 'wrong span 1'; +console.log(div$1, span$1); + +console.log(/*#__PURE__*/react.createElement("div", null)); +console.log(/*#__PURE__*/react.createElement("div", null, /*#__PURE__*/react.createElement("span", null))); + +const div = 'wrong div 2'; +const span = 'wrong span 2'; +console.log(div, span); diff --git a/test/form/samples/jsx/transpiles-native-elements/jsx.js b/test/form/samples/jsx/transpiles-native-elements/jsx.js new file mode 100644 index 00000000000..02159671af3 --- /dev/null +++ b/test/form/samples/jsx/transpiles-native-elements/jsx.js @@ -0,0 +1,5 @@ +const div = 'wrong div'; +const span = 'wrong span'; + +console.log(
); +console.log(
); diff --git a/test/form/samples/jsx/transpiles-native-elements/main.js b/test/form/samples/jsx/transpiles-native-elements/main.js new file mode 100644 index 00000000000..dfccae85926 --- /dev/null +++ b/test/form/samples/jsx/transpiles-native-elements/main.js @@ -0,0 +1,3 @@ +import "./other1.js"; +import "./jsx.js"; +import "./other2.js"; diff --git a/test/form/samples/jsx/transpiles-native-elements/other1.js b/test/form/samples/jsx/transpiles-native-elements/other1.js new file mode 100644 index 00000000000..d607c512add --- /dev/null +++ b/test/form/samples/jsx/transpiles-native-elements/other1.js @@ -0,0 +1,3 @@ +const div = 'wrong div 1'; +const span = 'wrong span 1'; +console.log(div, span); diff --git a/test/form/samples/jsx/transpiles-native-elements/other2.js b/test/form/samples/jsx/transpiles-native-elements/other2.js new file mode 100644 index 00000000000..25f1a5e7ad7 --- /dev/null +++ b/test/form/samples/jsx/transpiles-native-elements/other2.js @@ -0,0 +1,3 @@ +const div = 'wrong div 2'; +const span = 'wrong span 2'; +console.log(div, span); diff --git a/test/form/samples/jsx/transpiles-react-jsx/_config.js b/test/form/samples/jsx/transpiles-react-jsx/_config.js index e7413664d90..d9c8a8452c7 100644 --- a/test/form/samples/jsx/transpiles-react-jsx/_config.js +++ b/test/form/samples/jsx/transpiles-react-jsx/_config.js @@ -1,5 +1,4 @@ module.exports = defineTest({ - solo: true, description: 'transpiles JSX for react', options: { external: ['react', 'react/jsx-runtime'], diff --git a/test/function/samples/jsx/missing-jsx-export/_config.js b/test/function/samples/jsx/missing-jsx-export/_config.js index d814c6318ac..5c33d183a3a 100644 --- a/test/function/samples/jsx/missing-jsx-export/_config.js +++ b/test/function/samples/jsx/missing-jsx-export/_config.js @@ -1,19 +1,19 @@ const path = require('node:path'); -const ID_REACT = path.join(__dirname, 'react.js'); +const ID_REACT_JSX = path.join(__dirname, 'react-jsx.js'); const ID_MAIN = path.join(__dirname, 'main.js'); module.exports = defineTest({ description: 'throws when the JSX factory is not exported', options: { jsx: { - importSource: ID_REACT, + jsxImportSource: ID_REACT_JSX, preset: 'react-jsx' } }, error: { code: 'MISSING_JSX_EXPORT', - exporter: ID_REACT, + exporter: ID_REACT_JSX, frame: ` 1: const Foo = () => {}; 2: console.log(); @@ -25,10 +25,10 @@ module.exports = defineTest({ line: 2 }, message: - 'main.js (2:12): Export "jsx" is not defined in module "react.js" even though it is needed in "main.js" to provide JSX syntax. Please check your "jsx" option.', + 'main.js (2:12): Export "jsx" is not defined in module "react-jsx.js" even though it is needed in "main.js" to provide JSX syntax. Please check your "jsx" option.', names: ['jsx'], pos: 34, url: 'https://rollupjs.org/configuration-options/#jsx', - watchFiles: [ID_MAIN, ID_REACT] + watchFiles: [ID_MAIN, ID_REACT_JSX] } }); diff --git a/test/function/samples/jsx/missing-jsx-export/react.js b/test/function/samples/jsx/missing-jsx-export/react-jsx.js similarity index 100% rename from test/function/samples/jsx/missing-jsx-export/react.js rename to test/function/samples/jsx/missing-jsx-export/react-jsx.js From 9e56a5ad736daa8419053c7424025f9ee4a37f9b Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Tue, 10 Sep 2024 06:14:30 +0200 Subject: [PATCH 55/62] Add additional checks --- src/utils/options/normalizeInputOptions.ts | 38 +++++++++++++------ .../samples/jsx/unknown-mode/_config.js | 14 +++++++ .../samples/jsx/unknown-mode/_expected.js | 16 ++++++++ test/function/samples/jsx/unknown-mode/jsx.js | 1 + .../function/samples/jsx/unknown-mode/main.js | 2 + .../jsx/unnecessary-import-source/_config.js | 19 ++++++++++ .../unnecessary-import-source/_expected.js | 16 ++++++++ .../jsx/unnecessary-import-source/jsx.js | 1 + .../jsx/unnecessary-import-source/main.js | 2 + 9 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 test/function/samples/jsx/unknown-mode/_config.js create mode 100644 test/function/samples/jsx/unknown-mode/_expected.js create mode 100644 test/function/samples/jsx/unknown-mode/jsx.js create mode 100644 test/function/samples/jsx/unknown-mode/main.js create mode 100644 test/function/samples/jsx/unnecessary-import-source/_config.js create mode 100644 test/function/samples/jsx/unnecessary-import-source/_expected.js create mode 100644 test/function/samples/jsx/unnecessary-import-source/jsx.js create mode 100644 test/function/samples/jsx/unnecessary-import-source/main.js diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index 54452241ac8..f075dc35596 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -120,33 +120,49 @@ const getJsx = (config: InputOptions): NormalizedInputOptions['jsx'] => { const configJsx = config.jsx; if (!configJsx) return false; const configWithPreset = getOptionWithPreset(configJsx, jsxPresets, 'jsx', URL_JSX, 'false, '); - switch (configWithPreset.mode) { + const { factory, importSource, mode } = configWithPreset; + switch (mode) { case 'automatic': { return { - factory: configWithPreset.factory || 'React.createElement', - importSource: configWithPreset.importSource || null, + factory: factory || 'React.createElement', + importSource: importSource || null, jsxImportSource: configWithPreset.jsxImportSource || 'react/jsx-runtime', mode: 'automatic' }; } case 'preserve': { - // TODO Lukas throw if there is an importSource but neither factory nor fragment - // TODO Lukas throw if there is no importSource but a fragment or factory that is not a valid identifier (with optional ".") + if (importSource && !(factory || configWithPreset.fragment)) { + error( + logInvalidOption( + 'jsx', + URL_JSX, + 'when preserving JSX and specifying an importSource, you also need to specify a factory or fragment' + ) + ); + } return { - factory: configWithPreset.factory || null, + factory: factory || null, fragment: configWithPreset.fragment || null, - importSource: configWithPreset.importSource || null, + importSource: importSource || null, mode: 'preserve' }; } // case 'classic': default: { - // TODO Lukas throw if there is no importSource but a fragment or factory that is not a valid identifier - // TODO Lukas throw for unexpected mode + if (mode && mode !== 'classic') { + error( + logInvalidOption( + 'jsx.mode', + URL_JSX, + 'mode must be "automatic", "classic" or "preserve"', + mode + ) + ); + } return { - factory: configWithPreset.factory || 'React.createElement', + factory: factory || 'React.createElement', fragment: configWithPreset.fragment || 'React.Fragment', - importSource: configWithPreset.importSource || null, + importSource: importSource || null, mode: 'classic' }; } diff --git a/test/function/samples/jsx/unknown-mode/_config.js b/test/function/samples/jsx/unknown-mode/_config.js new file mode 100644 index 00000000000..c143e864cb7 --- /dev/null +++ b/test/function/samples/jsx/unknown-mode/_config.js @@ -0,0 +1,14 @@ +module.exports = defineTest({ + description: 'throws when using an unknown jsx mode', + options: { + jsx: { + mode: 'does-not-exist' + } + }, + error: { + code: 'INVALID_OPTION', + message: + 'Invalid value "does-not-exist" for option "jsx.mode" - mode must be "automatic", "classic" or "preserve".', + url: 'https://rollupjs.org/configuration-options/#jsx' + } +}); diff --git a/test/function/samples/jsx/unknown-mode/_expected.js b/test/function/samples/jsx/unknown-mode/_expected.js new file mode 100644 index 00000000000..0e6ceaa7ccd --- /dev/null +++ b/test/function/samples/jsx/unknown-mode/_expected.js @@ -0,0 +1,16 @@ +const Foo$2 = 'wrong Foo 1'; +const React$1 = 'wrong React 1'; +console.log(Foo$2, React$1); + +var react = { + createElement() { + console.log('createElement'); + } +}; + +const Foo$1 = () => {}; +console.log(/*#__PURE__*/react.createElement(Foo$1, null)); + +const Foo = 'wrong Foo 2'; +const React = 'wrong React 2'; +console.log(Foo, React); diff --git a/test/function/samples/jsx/unknown-mode/jsx.js b/test/function/samples/jsx/unknown-mode/jsx.js new file mode 100644 index 00000000000..e4c7f512867 --- /dev/null +++ b/test/function/samples/jsx/unknown-mode/jsx.js @@ -0,0 +1 @@ +export default 'unused'; diff --git a/test/function/samples/jsx/unknown-mode/main.js b/test/function/samples/jsx/unknown-mode/main.js new file mode 100644 index 00000000000..4b5671bbbac --- /dev/null +++ b/test/function/samples/jsx/unknown-mode/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); diff --git a/test/function/samples/jsx/unnecessary-import-source/_config.js b/test/function/samples/jsx/unnecessary-import-source/_config.js new file mode 100644 index 00000000000..b6019d29303 --- /dev/null +++ b/test/function/samples/jsx/unnecessary-import-source/_config.js @@ -0,0 +1,19 @@ +const path = require('node:path'); + +const ID_JSX = path.join(__dirname, 'jsx.js'); + +module.exports = defineTest({ + description: 'throws when preserving JSX syntax with an unnecessary import source', + options: { + jsx: { + importSource: ID_JSX, + mode: 'preserve' + } + }, + error: { + code: 'INVALID_OPTION', + message: + 'Invalid value for option "jsx" - when preserving JSX and specifying an importSource, you also need to specify a factory or fragment.', + url: 'https://rollupjs.org/configuration-options/#jsx' + } +}); diff --git a/test/function/samples/jsx/unnecessary-import-source/_expected.js b/test/function/samples/jsx/unnecessary-import-source/_expected.js new file mode 100644 index 00000000000..0e6ceaa7ccd --- /dev/null +++ b/test/function/samples/jsx/unnecessary-import-source/_expected.js @@ -0,0 +1,16 @@ +const Foo$2 = 'wrong Foo 1'; +const React$1 = 'wrong React 1'; +console.log(Foo$2, React$1); + +var react = { + createElement() { + console.log('createElement'); + } +}; + +const Foo$1 = () => {}; +console.log(/*#__PURE__*/react.createElement(Foo$1, null)); + +const Foo = 'wrong Foo 2'; +const React = 'wrong React 2'; +console.log(Foo, React); diff --git a/test/function/samples/jsx/unnecessary-import-source/jsx.js b/test/function/samples/jsx/unnecessary-import-source/jsx.js new file mode 100644 index 00000000000..e4c7f512867 --- /dev/null +++ b/test/function/samples/jsx/unnecessary-import-source/jsx.js @@ -0,0 +1 @@ +export default 'unused'; diff --git a/test/function/samples/jsx/unnecessary-import-source/main.js b/test/function/samples/jsx/unnecessary-import-source/main.js new file mode 100644 index 00000000000..4b5671bbbac --- /dev/null +++ b/test/function/samples/jsx/unnecessary-import-source/main.js @@ -0,0 +1,2 @@ +const Foo = () => {}; +console.log(); From 17eab3db358681be96bd0aca958c8375e888ca65 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Tue, 10 Sep 2024 06:30:33 +0200 Subject: [PATCH 56/62] Ensure CLI supports presets --- src/rollup/types.d.ts | 2 +- src/utils/options/mergeOptions.ts | 3 ++- test/cli/samples/jsx/_config.js | 4 ++++ test/cli/samples/jsx/_expected.js | 3 +++ test/cli/samples/jsx/main.js | 2 ++ 5 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 test/cli/samples/jsx/_config.js create mode 100644 test/cli/samples/jsx/_expected.js create mode 100644 test/cli/samples/jsx/main.js diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index dcbc41a542e..8dfbd7eb6d4 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -625,7 +625,7 @@ export interface InputOptions { experimentalLogSideEffects?: boolean; external?: ExternalOption; input?: InputOption; - jsx?: false | JsxOptions; + jsx?: false | JsxPreset | JsxOptions; logLevel?: LogLevelOption; makeAbsoluteExternalsRelative?: boolean | 'ifRelativeSource'; maxParallelFileOps?: number; diff --git a/src/utils/options/mergeOptions.ts b/src/utils/options/mergeOptions.ts index a1253f29a76..a9bded9aa71 100644 --- a/src/utils/options/mergeOptions.ts +++ b/src/utils/options/mergeOptions.ts @@ -18,6 +18,7 @@ import { generatedCodePresets, type GenericConfigObject, getOnLog, + jsxPresets, normalizePluginOption, objectifyOption, objectifyOptionWithPresets, @@ -140,7 +141,7 @@ function mergeInputOptions( overrides, 'jsx', ['preserve'], - objectifyOptionWithPresets(treeshakePresets, 'jsx', URL_JSX, 'false, ') + objectifyOptionWithPresets(jsxPresets, 'jsx', URL_JSX, 'false, ') ), logLevel: getOption('logLevel'), makeAbsoluteExternalsRelative: getOption('makeAbsoluteExternalsRelative'), diff --git a/test/cli/samples/jsx/_config.js b/test/cli/samples/jsx/_config.js new file mode 100644 index 00000000000..a837513c062 --- /dev/null +++ b/test/cli/samples/jsx/_config.js @@ -0,0 +1,4 @@ +module.exports = defineTest({ + description: 'supports jsx presets via CLI', + command: 'rollup -i main.js --jsx react --external react' +}); diff --git a/test/cli/samples/jsx/_expected.js b/test/cli/samples/jsx/_expected.js new file mode 100644 index 00000000000..abf18f99bc1 --- /dev/null +++ b/test/cli/samples/jsx/_expected.js @@ -0,0 +1,3 @@ +import react from 'react'; + +console.log(/*#__PURE__*/react.createElement("div", null, "Hello, world!")); diff --git a/test/cli/samples/jsx/main.js b/test/cli/samples/jsx/main.js new file mode 100644 index 00000000000..877d1e6d90b --- /dev/null +++ b/test/cli/samples/jsx/main.js @@ -0,0 +1,2 @@ +import React from 'react'; +console.log(
Hello, world!
); From f139fef11adf6476e1e5a35b11a73328a7f92962 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 20 Sep 2024 13:45:11 +0200 Subject: [PATCH 57/62] Add JSX options to REPL --- docs/repl/examples/00/example.json | 7 ++- docs/repl/examples/00/modules/main.js | 19 ++++++-- docs/repl/examples/{01 => 00}/modules/qux.js | 0 docs/repl/examples/01/example.json | 7 +-- docs/repl/examples/01/modules/main.js | 19 ++------ .../repl/examples/{00 => 01}/modules/maths.js | 0 docs/repl/stores/options.ts | 46 ++++++++++++++++++- 7 files changed, 70 insertions(+), 28 deletions(-) rename docs/repl/examples/{01 => 00}/modules/qux.js (100%) rename docs/repl/examples/{00 => 01}/modules/maths.js (100%) diff --git a/docs/repl/examples/00/example.json b/docs/repl/examples/00/example.json index 552e7b13123..64ee77b4684 100644 --- a/docs/repl/examples/00/example.json +++ b/docs/repl/examples/00/example.json @@ -1,6 +1,9 @@ { - "title": "Tree-shaking", + "title": "Named exports", "options": { - "treeshake": true + "output": { + "exports": "auto", + "esModule": "if-default-prop" + } } } diff --git a/docs/repl/examples/00/modules/main.js b/docs/repl/examples/00/modules/main.js index 140917331c5..a88f397e682 100644 --- a/docs/repl/examples/00/modules/main.js +++ b/docs/repl/examples/00/modules/main.js @@ -1,4 +1,17 @@ -// TREE-SHAKING -import { cube } from './maths.js'; +// NAMED EXPORTS +// There are many ways to export bindings +// from an ES2015 module +export var foo = 1; -console.log(cube(5)); // 125 +export function bar() { + // try changing this to `foo++` + // when generating CommonJS + return foo; +} + +function baz() { + return bar(); +} + +export * from './qux'; +export { baz }; diff --git a/docs/repl/examples/01/modules/qux.js b/docs/repl/examples/00/modules/qux.js similarity index 100% rename from docs/repl/examples/01/modules/qux.js rename to docs/repl/examples/00/modules/qux.js diff --git a/docs/repl/examples/01/example.json b/docs/repl/examples/01/example.json index 64ee77b4684..552e7b13123 100644 --- a/docs/repl/examples/01/example.json +++ b/docs/repl/examples/01/example.json @@ -1,9 +1,6 @@ { - "title": "Named exports", + "title": "Tree-shaking", "options": { - "output": { - "exports": "auto", - "esModule": "if-default-prop" - } + "treeshake": true } } diff --git a/docs/repl/examples/01/modules/main.js b/docs/repl/examples/01/modules/main.js index a88f397e682..140917331c5 100644 --- a/docs/repl/examples/01/modules/main.js +++ b/docs/repl/examples/01/modules/main.js @@ -1,17 +1,4 @@ -// NAMED EXPORTS -// There are many ways to export bindings -// from an ES2015 module -export var foo = 1; +// TREE-SHAKING +import { cube } from './maths.js'; -export function bar() { - // try changing this to `foo++` - // when generating CommonJS - return foo; -} - -function baz() { - return bar(); -} - -export * from './qux'; -export { baz }; +console.log(cube(5)); // 125 diff --git a/docs/repl/examples/00/modules/maths.js b/docs/repl/examples/01/modules/maths.js similarity index 100% rename from docs/repl/examples/00/modules/maths.js rename to docs/repl/examples/01/modules/maths.js diff --git a/docs/repl/stores/options.ts b/docs/repl/stores/options.ts index 0f1fd0371a4..b8207c94e7f 100644 --- a/docs/repl/stores/options.ts +++ b/docs/repl/stores/options.ts @@ -114,6 +114,7 @@ export const useOptions = defineStore('options2', () => { return value != null && interopFormats.has(value); }); const externalImports = computed(() => rollupOutputStore.output?.externalImports || []); + const isJsxEnabled = computed(() => optionJsx.value.value === true); const isTreeshakeEnabled = computed(() => [undefined, true].includes(optionTreeshake.value.value as any) ); @@ -375,6 +376,39 @@ export const useOptions = defineStore('options2', () => { defaultValue: false, name: 'shimMissingExports' }); + const optionJsx = getSelect({ + defaultValue: false, + name: 'jsx', + options: () => [false, true, 'preserve', 'preserve-react', 'react', 'react-jsx'] + }); + const optionJsxFactory = getString({ + available: isJsxEnabled, + name: 'jsx.factory' + }); + const optionJsxFragment = getString({ + available: computed(() => isJsxEnabled.value && optionJsxMode.value.value !== 'automatic'), + name: 'jsx.fragment' + }); + const optionJsxImportSource = getString({ + available: isJsxEnabled, + name: 'jsx.importSource' + }); + const optionJsxJsxImportSource = getString({ + available: computed(() => isJsxEnabled.value && optionJsxMode.value.value === 'automatic'), + name: 'jsx.jsxImportSource' + }); + const optionJsxMode = getSelect({ + available: isJsxEnabled, + defaultValue: 'classic', + name: 'jsx.mode', + options: () => ['classic', 'automatic', 'preserve'] + }); + const optionJsxPreset = getSelect({ + available: isJsxEnabled, + defaultValue: null, + name: 'jsx.preset', + options: () => [null, 'preserve', 'preserve-react', 'react', 'react-jsx'] + }); const optionTreeshake = getSelect({ defaultValue: true, name: 'treeshake', @@ -422,6 +456,13 @@ export const useOptions = defineStore('options2', () => { const optionList: OptionType[] = [ optionContext, optionExperimentalLogSideEffects, + optionJsx, + optionJsxMode, + optionJsxFactory, + optionJsxFragment, + optionJsxImportSource, + optionJsxJsxImportSource, + optionJsxPreset, optionOutputAmdAutoId, optionOutputAmdBasePath, optionOutputAmdDefine, @@ -511,7 +552,8 @@ export const useOptions = defineStore('options2', () => { while ((key = path.shift())) { subOptions = subOptions?.[key]; } - value.value = name === 'treeshake' && typeof subOptions === 'object' ? true : subOptions; + value.value = + ['jsx', 'treeshake'].includes(name) && typeof subOptions === 'object' ? true : subOptions; } } }; @@ -652,7 +694,7 @@ function getOptionsObject(options: Ref): Ref { let key: string | undefined; let subOptions: any = object; while ((key = path.shift())) { - // Special logic to handle treeshake option + // Special logic to handle jsx/treeshake option if (subOptions[key] === true) { subOptions[key] = {}; } From 9be895bbce0b321951e820a507fb6bfadb3c3144 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 20 Sep 2024 15:13:13 +0200 Subject: [PATCH 58/62] Add documentation --- docs/configuration-options/index.md | 266 +++++++++++++++++++++++----- 1 file changed, 217 insertions(+), 49 deletions(-) diff --git a/docs/configuration-options/index.md b/docs/configuration-options/index.md index f55a3551297..4a850a4c743 100755 --- a/docs/configuration-options/index.md +++ b/docs/configuration-options/index.md @@ -12,7 +12,7 @@ title: Configuration Options | | | | --: | :-- | -| Type: | `(string \| RegExp)[]\| RegExp\| string\| (id: string, parentId: string, isResolved: boolean) => boolean` | +| Type: | `(string \| RegExp)[] \| RegExp \| string \| (id: string, parentId: string, isResolved: boolean) => boolean` | | CLI: | `-e`/`--external ` | Either a function that takes an `id` and returns `true` (external) or `false` (not external), or an `Array` of module IDs, or regular expressions to match module IDs, that should remain external to the bundle. Can also be just a single ID or regular expression. The matched IDs should be either: @@ -85,10 +85,10 @@ The conversion back to a relative import is done as if `output.file` or `output. ### input -| | | -| ----: | :------------------------------------------------------ | -| Type: | `string \| string []\| { [entryName: string]: string }` | -| CLI: | `-i`/`--input ` | +| | | +| ----: | :------------------------------------------------------- | +| Type: | `string \| string [] \| { [entryName: string]: string }` | +| CLI: | `-i`/`--input ` | The bundle's entry point(s) (e.g. your `main.js` or `app.js` or `index.js`). If you provide an array of entry points or an object mapping names to entry points, they will be bundled to separate output chunks. Unless the [`output.file`](#output-file) option is used, generated chunk names will follow the [`output.entryFileNames`](#output-entryfilenames) option. When using the object form, the `[name]` portion of the file name will be the name of the object property while for the array form, it will be the file name of the entry point. @@ -171,11 +171,179 @@ rollup "main entry"="src/entry 1.js" "src/other entry.js" --format es ### jsx -| | | -| -------: | :----------------------------------------------- | -| Type: | `false \| "preserve" \| JsxPreset \| JsxOptions` | -| CLI: | `--jsx `/`--no-jsx` | -| Default: | `false` | +| | | +| -------: | :--------------------------------- | +| Type: | `false \| JsxPreset \| JsxOptions` | +| CLI: | `--jsx `/`--no-jsx` | +| Default: | `false` | + +```typescript +type JsxPreset = 'react' | 'react-jsx' | 'preserve' | 'preserve-react'; + +type JsxOptions = + | { + mode: 'preserve'; + factory: string | null; + fragment: string | null; + importSource: string | null; + preset: JsxPreset | null; + } + | { + mode: 'classic'; + factory: string; + fragment: string; + importSource: string | null; + preset: JsxPreset | null; + } + | { + mode: 'automatic'; + factory: string; + importSource: string; + jsxImportSource: string; + preset: JsxPreset | null; + }; +``` + +Allows Rollup to process JSX syntax to either preserve or transform it depending on the [`jsx.mode`](#jsx-mode). If set to `false`, an error will be thrown if JSX syntax is encountered. You may also choose a preset that will set all options together: + +- `"react"`: For transpiling JSX to `React.createElement` calls, where `React` is the default import from `"react"`. This is the same as setting `"jsx": "react"` in the TypeScript compiler options. + ```js + ({ + mode: 'classic', + factory: 'React.createElement', + fragment: 'React.Fragment', + importSource: 'react' + }); + ``` +- `"react-jsx"`: This will use the new optimized React transformation introduced with React 17 and is similar to setting `"jsx": "react-jsx"` in the TypeScript compiler options. + ```js + ({ + mode: 'automatic', + factory: 'React.createElement', + importSource: 'react', + jsxImportSource: 'react/jsx-runtime' + }); + ``` +- `"preserve"`: This will preserve JSX in the output. This will still tree-shake unused JSX code and may rename JSX identifiers if there are conflicts in the output. + ```js + ({ + mode: 'preserve', + factory: null, + fragment: null, + importSource: null + }); + ``` +- `"preserve-react"`: This will preserve JSX in the output but ensure that the default export of `"react"` is in scope as the `React` variable. + ```js + ({ + mode: 'preserve', + factory: 'React.createElement', + fragment: 'React.Fragment', + importSource: 'react' + }); + ``` + +#### jsx.mode + +| | | +| -------: | :--------------------------------------- | +| Type: | `"preserve" \| "classic" \| "automatic"` | +| CLI: | `--jsx.mode ` | +| Default: | `"classic"` | + +This will determine how JSX is processed: + +- `"preserve"`: Will keep JSX syntax in the output. +- `"classic"`: This will perform a JSX transformation as it is needed by older React versions or other frameworks like for instance [Preact](https://preactjs.com). As an example, here is how you would configure jsx for Preact: + + ```js + ({ + mode: 'classic', + factory: 'h', + fragment: 'Fragment', + importSource: 'preact' + }); + ``` + + This would perform the following transformation: + + ```jsx + // input + console.log(
hello
); + + // output + import { h } from 'preact'; + console.log(/*#__PURE__*/ h('div', null, 'hello')); + ``` + +- `"automatic"`: This will perform a JSX transformation using the [new JSX transform](https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) introduced with React 17. In this mode, Rollup will try to use helpers from the [`jsx.jsxImportSource`](#jsx-jsximportsource) to transform JSX. As there are certain edge cases, this mode may still fall back to using the classic transformations when [using the `key` property together with spread attributes](https://github.com/facebook/react/issues/20031#issuecomment-710346866). To this end, you can still specify `jsx.importSource`, `jsx.factory`, and `jsx.fragment` to configure classic mode. + +#### jsx.factory + +| | | +| -------: | :-------------------------------- | +| Type: | `string \| null` | +| CLI: | `--jsx.factory ` | +| Default: | `"React.createElement"` or `null` | + +The function Rollup uses to create JSX elements in `"classic"` mode or as a fallback in `"automatic"` mode. This is usually `React.createElement` for React or `h` for other frameworks. In `"preserve"` mode, this will ensure that the factory is present if a [`jsx.importSource`](#jsx-importsource) is specified, or otherwise not overridden by local variables. Only in `"preserve"` mode it is possible to set this value to `null`, in which case Rollup will not take care to keep any particular factory function in scope. + +If the value contains a `"."` like `React.createElement` and an `jsx.importSource` is specified, Rollup will assume that the left part, e.g. `React`, refers to the default export of the `jsx.importSource`. Otherwise, Rollup assumes it is a named export. + +#### jsx.fragment + +| | | +| -------: | :--------------------------- | +| Type: | `string \| null` | +| CLI: | `--jsx.fragment ` | +| Default: | `"React.Fragment"` or `null` | + +The element function Rollup uses to create JSX fragments. This is usually `React.Fragment` for React or `Fragment` for other frameworks. In `"preserve"` mode, this will ensure that the fragment is present as an import if an [`jsx.importSource`](#jsx-importsource) is specified, or otherwise not overridden by local variables. Only in `"preserve"` mode it is possible to set this value to `null`, in which case Rollup will not take care to keep any particular fragment function in scope. + +If the value contains a `"."` like `React.Fragment` and an `jsx.importSource` is specified, Rollup will assume that the left part, e.g. `React`, refers to the default export of the `jsx.importSource`. Otherwise, Rollup assumes it is a named export. + +#### jsx.importSource + +| | | +| -------: | :----------------------------- | +| Type: | `string \| null` | +| CLI: | `--jsx.importSource ` | +| Default: | `null` | + +Where to import the element factory function and/or the fragment element from. If left to `null`, Rollup will assume that `factory` and `fragment` refer to global variables and make sure they are not shadowed by local variables. + +#### jsx.jsxImportSource + +| | | +| -------: | :-------------------------------- | +| Type: | `string` | +| CLI: | `--jsx.jsxImportSource ` | +| Default: | `"react/jsx-runtime"` | + +When using `"automatic"` mode, this will specify from where to import the `jsx`, `jsxs` and `Fragment` helpers needed for that transformation. It is not possible to get those from a global variable. + +#### jsx.preset + +| | | +| ----: | :--------------------- | +| Type: | JsxPreset | +| CLI: | `--jsx.preset ` | + +Allows choosing one of the presets listed above while overriding some options. + +```js twoslash +// ---cut-start--- +/** @type {import('rollup').RollupOptions} */ +// ---cut-end--- +export default { + jsx: { + preset: 'react', + importSource: 'preact', + factory: 'h' + } + // ... +}; +``` ### output.dir @@ -216,7 +384,7 @@ Specifies the format of the generated bundle. One of the following: | | | | --: | :-- | -| Type: | `{ [id: string]: string }\| ((id: string) => string)` | +| Type: | `{ [id: string]: string } \| ((id: string) => string)` | | CLI: | `-g`/`--globals ` | Specifies `id: variableName` pairs necessary for external imports in `umd`/`iife` bundles. For example, in a case like this… @@ -447,7 +615,7 @@ When using the CLI, errors will still be printed to the console as they are not | | | | --: | :-- | -| Type: | `boolean\| "ifRelativeSource"` | +| Type: | `boolean \| "ifRelativeSource"` | | CLI: | `--makeAbsoluteExternalsRelative`/`--no-makeAbsoluteExternalsRelative` | | Default: | `"ifRelativeSource"` | @@ -574,11 +742,11 @@ See [`onLog`](#onlog) for more information. ### output.assetFileNames -| | | -| -------: | :--------------------------------------------------- | -| Type: | `string\| ((assetInfo: PreRenderedAsset) => string)` | -| CLI: | `--assetFileNames ` | -| Default: | `"assets/[name]-[hash][extname]"` | +| | | +| -------: | :---------------------------------------------------- | +| Type: | `string \| ((assetInfo: PreRenderedAsset) => string)` | +| CLI: | `--assetFileNames ` | +| Default: | `"assets/[name]-[hash][extname]"` | ```typescript interface PreRenderedAsset { @@ -600,10 +768,10 @@ Forward slashes `/` can be used to place files in sub-directories. When using a ### output.banner/output.footer -| | | -| ----: | :--------------------------------------------------------------- | -| Type: | `string \| ((chunk: RenderedChunk) => string\| Promise)` | -| CLI: | `--banner`/`--footer ` | +| | | +| --: | :-- | +| Type: | `string \| ((chunk: RenderedChunk) => string \| Promise)` | +| CLI: | `--banner`/`--footer ` | See the [`renderChunk`](../plugin-development/index.md#renderchunk) hook for the `RenderedChunk` type. @@ -766,7 +934,7 @@ Whether to add import attributes to external imports in the output if the output | | | | --: | :-- | -| Type: | `"es5" \| "es2015"\| { arrowFunctions?: boolean, constBindings?: boolean, objectShorthand?: boolean, preset?: "es5"\| "es2015", reservedNamesAsProps?: boolean, symbols?: boolean }` | +| Type: | `"es5" \| "es2015" \| { arrowFunctions?: boolean, constBindings?: boolean, objectShorthand?: boolean, preset?: "es5" \| "es2015", reservedNamesAsProps?: boolean, symbols?: boolean }` | | CLI: | `--generatedCode ` | | Default: | `"es5"` | @@ -988,7 +1156,7 @@ This will inline dynamic imports instead of creating new chunks to create a sing | | | | --: | :-- | -| Type: | `"compat" \| "auto"\| "esModule"\| "default"\| "defaultOnly"\| ((id: string) => "compat"\| "auto"\| "esModule"\| "default"\| "defaultOnly")` | +| Type: | `"compat" \| "auto" \| "esModule" \| "default" \| "defaultOnly" \| ((id: string) => "compat" \| "auto" \| "esModule" \| "default" \| "defaultOnly")` | | CLI: | `--interop ` | | Default: | `"default"` | @@ -1247,10 +1415,10 @@ There are some additional options that have an effect on the generated interop c ### output.intro/output.outro -| | | -| ----: | :--------------------------------------------------------------- | -| Type: | `string \| ((chunk: RenderedChunk) => string\| Promise)` | -| CLI: | `--intro`/`--outro ` | +| | | +| --: | :-- | +| Type: | `string \| ((chunk: RenderedChunk) => string \| Promise)` | +| CLI: | `--intro`/`--outro ` | Similar to [`output.banner/output.footer`](#output-banner-output-footer), except that the code goes _inside_ any format-specific wrapper. @@ -1561,7 +1729,7 @@ This option is particularly useful while using plugins such as `@rollup/plugin-n | | | | -------: | :---------------------------------- | -| Type: | `boolean \| 'inline'\| 'hidden'` | +| Type: | `boolean \| 'inline' \| 'hidden'` | | CLI: | `-m`/`--sourcemap`/`--no-sourcemap` | | Default: | `false` | @@ -1704,7 +1872,7 @@ This option specifies the directory name for "virtual" files that might be emitt | | | | --: | :-- | -| Type: | `"strict" \| "allow-extension" \| "exports-only"\| false` | +| Type: | `"strict" \| "allow-extension" \| "exports-only" \| false` | | CLI: | `--preserveEntrySignatures `/`--no-preserveEntrySignatures` | | Default: | `"exports-only"` | @@ -1983,11 +2151,11 @@ See also [`output.interop`](#output-interop). ### output.exports -| | | -| -------: | :--------------------------------------- | -| Type: | `"auto" \| "default"\| "named"\| "none"` | -| CLI: | `--exports ` | -| Default: | `'auto'` | +| | | +| -------: | :----------------------------------------- | +| Type: | `"auto" \| "default" \| "named" \| "none"` | +| CLI: | `--exports ` | +| Default: | `'auto'` | What export mode to use. Defaults to `auto`, which guesses your intentions based on what the `input` module exports: @@ -2240,7 +2408,7 @@ If this option is provided, bundling will not fail if bindings are imported from | | | | -------: | :--------------------------------------------------- | | Type: | `boolean \| TreeshakingPreset \| TreeshakingOptions` | -| CLI: | `--treeshake`/`--no-treeshake` | +| CLI: | `--treeshake `/`--no-treeshake` | | Default: | `true` | ```typescript @@ -2406,7 +2574,7 @@ styled().div(); // removed | | | | --: | :-- | -| Type: | `boolean\| "no-external"\| string[]\| (id: string, external: boolean) => boolean` | +| Type: | `boolean \| "no-external" \| string[] \| (id: string, external: boolean) => boolean` | | CLI: | `--treeshake.moduleSideEffects`/`--no-treeshake.moduleSideEffects`/`--treeshake.moduleSideEffects no-external` | | Default: | `true` | @@ -2494,10 +2662,10 @@ Note that despite the name, this option does not "add" side effects to modules t #### treeshake.preset -| | | -| ----: | :--------------------------------------- | -| Type: | `"smallest" \| "safest"\| "recommended"` | -| CLI: | `--treeshake `
| +| | | +| ----: | :---------------------------------------- | +| Type: | `"smallest" \| "safest" \| "recommended"` | +| CLI: | `--treeshake `
| Allows choosing one of the presets listed above while overriding some options. @@ -2518,7 +2686,7 @@ export default { | | | | --: | :-- | -| Type: | `boolean\| 'always'` | +| Type: | `boolean \| 'always'` | | CLI: | `--treeshake.propertyReadSideEffects`/`--no-treeshake.propertyReadSideEffects` | | Default: | `true` | @@ -2741,10 +2909,10 @@ Whether to clear the screen when a rebuild is triggered. ### watch.exclude -| | | -| ----: | :--------------------------------------- | -| Type: | `string \| RegExp\| (string\| RegExp)[]` | -| CLI: | `--watch.exclude ` | +| | | +| ----: | :----------------------------------------- | +| Type: | `string \| RegExp \| (string \| RegExp)[]` | +| CLI: | `--watch.exclude ` | Prevent files from being watched: @@ -2763,10 +2931,10 @@ export default { ### watch.include -| | | -| ----: | :--------------------------------------- | -| Type: | `string \| RegExp\| (string\| RegExp)[]` | -| CLI: | `--watch.include ` | +| | | +| ----: | :----------------------------------------- | +| Type: | `string \| RegExp \| (string \| RegExp)[]` | +| CLI: | `--watch.include ` | Limit the file-watching to certain files. Note that this only filters the module graph but does not allow adding additional watch files: From 62296009cf4dee515e002e7f92a8244b55bc78a6 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Tue, 1 Oct 2024 06:56:52 +0200 Subject: [PATCH 59/62] Improve coverage --- src/ast/nodes/JSXAttribute.ts | 9 +++------ src/ast/nodes/JSXIdentifier.ts | 11 ++++------- src/ast/scopes/GlobalScope.ts | 4 ---- src/ast/scopes/Scope.ts | 9 --------- src/utils/options/mergeOptions.ts | 13 ++----------- src/utils/options/normalizeInputOptions.ts | 2 +- .../transpiles-automatic-with-defaults/_config.js | 7 +++++++ .../transpiles-automatic-with-defaults/_expected.js | 11 +++++++++++ .../jsx/transpiles-automatic-with-defaults/main.js | 8 ++++++++ .../jsx/transpiles-classic-with-defaults/_config.js | 7 +++++++ .../transpiles-classic-with-defaults/_expected.js | 8 ++++++++ .../jsx/transpiles-classic-with-defaults/main.js | 8 ++++++++ 12 files changed, 59 insertions(+), 38 deletions(-) create mode 100644 test/form/samples/jsx/transpiles-automatic-with-defaults/_config.js create mode 100644 test/form/samples/jsx/transpiles-automatic-with-defaults/_expected.js create mode 100644 test/form/samples/jsx/transpiles-automatic-with-defaults/main.js create mode 100644 test/form/samples/jsx/transpiles-classic-with-defaults/_config.js create mode 100644 test/form/samples/jsx/transpiles-classic-with-defaults/_expected.js create mode 100644 test/form/samples/jsx/transpiles-classic-with-defaults/main.js diff --git a/src/ast/nodes/JSXAttribute.ts b/src/ast/nodes/JSXAttribute.ts index 0b2ab72b50c..b16287d9de2 100644 --- a/src/ast/nodes/JSXAttribute.ts +++ b/src/ast/nodes/JSXAttribute.ts @@ -1,4 +1,5 @@ import type MagicString from 'magic-string'; +import { BLANK } from '../../utils/blank'; import { stringifyObjectKeyIfNeeded } from '../../utils/identifierHelpers'; import type { NodeRenderOptions, RenderOptions } from '../../utils/renderHelpers'; import type JSXElement from './JSXElement'; @@ -15,13 +16,9 @@ export default class JSXAttribute extends NodeBase { name!: JSXIdentifier | JSXNamespacedName; value!: Literal | JSXExpressionContainer | JSXElement | JSXFragment | null; - render( - code: MagicString, - options: RenderOptions, - { jsxMode = 'preserve' }: NodeRenderOptions = {} - ): void { + render(code: MagicString, options: RenderOptions, { jsxMode }: NodeRenderOptions = BLANK): void { super.render(code, options); - if (jsxMode !== 'preserve') { + if ((['classic', 'automatic'] as (string | undefined)[]).includes(jsxMode)) { const { name, value } = this; const key = name instanceof JSXIdentifier ? name.name : `${name.namespace.name}:${name.name.name}`; diff --git a/src/ast/nodes/JSXIdentifier.ts b/src/ast/nodes/JSXIdentifier.ts index 4cee922aa75..f7576328311 100644 --- a/src/ast/nodes/JSXIdentifier.ts +++ b/src/ast/nodes/JSXIdentifier.ts @@ -1,9 +1,7 @@ import type MagicString from 'magic-string'; import type { NormalizedJsxOptions } from '../../rollup/types'; import type { RenderOptions } from '../../utils/renderHelpers'; -import type JSXClosingElement from './JSXClosingElement'; import type JSXMemberExpression from './JSXMemberExpression'; -import type JSXOpeningElement from './JSXOpeningElement'; import type * as NodeType from './NodeType'; import IdentifierBase from './shared/IdentifierBase'; @@ -54,11 +52,9 @@ export default class JSXIdentifier extends IdentifierBase { switch (this.parent.type) { case 'JSXOpeningElement': case 'JSXClosingElement': { - return (this.parent as JSXOpeningElement | JSXClosingElement).name === this - ? this.name.startsWith(this.name.charAt(0).toUpperCase()) - ? IdentifierType.Reference - : IdentifierType.NativeElementName - : IdentifierType.Other; + return this.name.startsWith(this.name.charAt(0).toUpperCase()) + ? IdentifierType.Reference + : IdentifierType.NativeElementName; } case 'JSXMemberExpression': { return (this.parent as JSXMemberExpression).object === this @@ -70,6 +66,7 @@ export default class JSXIdentifier extends IdentifierBase { return IdentifierType.Other; } default: { + /* istanbul ignore next */ throw new Error(`Unexpected parent node type for JSXIdentifier: ${this.parent.type}`); } } diff --git a/src/ast/scopes/GlobalScope.ts b/src/ast/scopes/GlobalScope.ts index b31ef03ba2b..08c94f0f879 100644 --- a/src/ast/scopes/GlobalScope.ts +++ b/src/ast/scopes/GlobalScope.ts @@ -11,10 +11,6 @@ export default class GlobalScope extends Scope { this.variables.set('undefined', new UndefinedVariable()); } - findGlobal(name: string): Variable { - return this.findVariable(name); - } - findVariable(name: string): Variable { let variable = this.variables.get(name); if (!variable) { diff --git a/src/ast/scopes/Scope.ts b/src/ast/scopes/Scope.ts index 9d0146de2f8..eaeea352d7d 100644 --- a/src/ast/scopes/Scope.ts +++ b/src/ast/scopes/Scope.ts @@ -54,15 +54,6 @@ export default class Scope { return this.variables.has(name); } - /** - * This allows us to protect the name of a variable by pretending we also - * include a global variable of the same name. - */ - findGlobal(_name: string): void { - /* istanbul ignore next */ - throw new Error('Internal Error: findGlobal needs to be implemented by a subclass'); - } - findVariable(_name: string): Variable { /* istanbul ignore next */ throw new Error('Internal Error: findVariable needs to be implemented by a subclass'); diff --git a/src/utils/options/mergeOptions.ts b/src/utils/options/mergeOptions.ts index a9bded9aa71..29d7ff0e842 100644 --- a/src/utils/options/mergeOptions.ts +++ b/src/utils/options/mergeOptions.ts @@ -8,7 +8,6 @@ import type { RollupCache, RollupOptions } from '../../rollup/types'; -import { EMPTY_ARRAY } from '../blank'; import { ensureArray } from '../ensureArray'; import { getLogger } from '../logger'; import { LOGLEVEL_INFO } from '../logging'; @@ -140,7 +139,6 @@ function mergeInputOptions( config, overrides, 'jsx', - ['preserve'], objectifyOptionWithPresets(jsxPresets, 'jsx', URL_JSX, 'false, ') ), logLevel: getOption('logLevel'), @@ -159,7 +157,6 @@ function mergeInputOptions( config, overrides, 'treeshake', - EMPTY_ARRAY, objectifyOptionWithPresets(treeshakePresets, 'treeshake', URL_TREESHAKE, 'false, true, ') ), watch: getWatch(config, overrides) @@ -181,13 +178,8 @@ const getObjectOption = ( config: T, overrides: T, name: keyof T, - nonObjectValues: readonly unknown[], objectifyValue = objectifyOption ): any => { - const primitiveValue = overrides[name] ?? config[name]; - if (nonObjectValues.includes(primitiveValue)) { - return primitiveValue; - } const commandOption = normalizeObjectOptionValue(overrides[name], objectifyValue); const configOption = normalizeObjectOptionValue(config[name], objectifyValue); if (commandOption !== undefined) { @@ -197,7 +189,7 @@ const getObjectOption = ( }; export const getWatch = (config: InputOptions, overrides: InputOptions) => - config.watch !== false && getObjectOption(config, overrides, 'watch', EMPTY_ARRAY); + config.watch !== false && getObjectOption(config, overrides, 'watch'); export const isWatchEnabled = (optionValue: unknown): boolean => { if (Array.isArray(optionValue)) { @@ -236,7 +228,7 @@ async function mergeOutputOptions( ): Promise { const getOption = (name: keyof OutputOptions): any => overrides[name] ?? config[name]; const outputOptions: CompleteOutputOptions = { - amd: getObjectOption(config, overrides, 'amd', EMPTY_ARRAY), + amd: getObjectOption(config, overrides, 'amd'), assetFileNames: getOption('assetFileNames'), banner: getOption('banner'), chunkFileNames: getOption('chunkFileNames'), @@ -259,7 +251,6 @@ async function mergeOutputOptions( config, overrides, 'generatedCode', - EMPTY_ARRAY, objectifyOptionWithPresets( generatedCodePresets, 'output.generatedCode', diff --git a/src/utils/options/normalizeInputOptions.ts b/src/utils/options/normalizeInputOptions.ts index f075dc35596..85127200c0e 100644 --- a/src/utils/options/normalizeInputOptions.ts +++ b/src/utils/options/normalizeInputOptions.ts @@ -125,7 +125,7 @@ const getJsx = (config: InputOptions): NormalizedInputOptions['jsx'] => { case 'automatic': { return { factory: factory || 'React.createElement', - importSource: importSource || null, + importSource: importSource || 'react', jsxImportSource: configWithPreset.jsxImportSource || 'react/jsx-runtime', mode: 'automatic' }; diff --git a/test/form/samples/jsx/transpiles-automatic-with-defaults/_config.js b/test/form/samples/jsx/transpiles-automatic-with-defaults/_config.js new file mode 100644 index 00000000000..77000dc3995 --- /dev/null +++ b/test/form/samples/jsx/transpiles-automatic-with-defaults/_config.js @@ -0,0 +1,7 @@ +module.exports = defineTest({ + description: 'transpiles JSX for react', + options: { + external: ['react', 'react/jsx-runtime'], + jsx: { mode: 'automatic' } + } +}); diff --git a/test/form/samples/jsx/transpiles-automatic-with-defaults/_expected.js b/test/form/samples/jsx/transpiles-automatic-with-defaults/_expected.js new file mode 100644 index 00000000000..4181ccce6f9 --- /dev/null +++ b/test/form/samples/jsx/transpiles-automatic-with-defaults/_expected.js @@ -0,0 +1,11 @@ +import { jsx, Fragment, jsxs } from 'react/jsx-runtime'; +import react from 'react'; + +const Foo = () => {}; +const obj = { key: '2' }; + +console.log(/*#__PURE__*/jsx(Foo, {})); +console.log(/*#__PURE__*/jsx(Fragment, { children: /*#__PURE__*/jsx(Foo, {}) })); +console.log(/*#__PURE__*/jsxs(Foo, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); +console.log(/*#__PURE__*/jsxs(Fragment, { children: [/*#__PURE__*/jsx(Foo, {}), /*#__PURE__*/jsx(Foo, {})] })); +console.log(/*#__PURE__*/react.createElement(Foo, Object.assign({}, obj, { key: "1" }))); diff --git a/test/form/samples/jsx/transpiles-automatic-with-defaults/main.js b/test/form/samples/jsx/transpiles-automatic-with-defaults/main.js new file mode 100644 index 00000000000..13f357d5f77 --- /dev/null +++ b/test/form/samples/jsx/transpiles-automatic-with-defaults/main.js @@ -0,0 +1,8 @@ +const Foo = () => {}; +const obj = { key: '2' }; + +console.log(); +console.log(<>); +console.log(); +console.log(<>); +console.log(); diff --git a/test/form/samples/jsx/transpiles-classic-with-defaults/_config.js b/test/form/samples/jsx/transpiles-classic-with-defaults/_config.js new file mode 100644 index 00000000000..61589a99124 --- /dev/null +++ b/test/form/samples/jsx/transpiles-classic-with-defaults/_config.js @@ -0,0 +1,7 @@ +module.exports = defineTest({ + description: 'transpiles JSX for react', + options: { + external: ['react', 'react/jsx-runtime'], + jsx: { mode: 'classic' } + } +}); diff --git a/test/form/samples/jsx/transpiles-classic-with-defaults/_expected.js b/test/form/samples/jsx/transpiles-classic-with-defaults/_expected.js new file mode 100644 index 00000000000..758900d85bb --- /dev/null +++ b/test/form/samples/jsx/transpiles-classic-with-defaults/_expected.js @@ -0,0 +1,8 @@ +const Foo = () => {}; +const obj = { key: '2' }; + +console.log(/*#__PURE__*/React.createElement(Foo, null)); +console.log(/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Foo, null))); +console.log(/*#__PURE__*/React.createElement(Foo, null, /*#__PURE__*/React.createElement(Foo, null), /*#__PURE__*/React.createElement(Foo, null))); +console.log(/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Foo, null), /*#__PURE__*/React.createElement(Foo, null))); +console.log(/*#__PURE__*/React.createElement(Foo, Object.assign({}, obj, { key: "1" }))); diff --git a/test/form/samples/jsx/transpiles-classic-with-defaults/main.js b/test/form/samples/jsx/transpiles-classic-with-defaults/main.js new file mode 100644 index 00000000000..13f357d5f77 --- /dev/null +++ b/test/form/samples/jsx/transpiles-classic-with-defaults/main.js @@ -0,0 +1,8 @@ +const Foo = () => {}; +const obj = { key: '2' }; + +console.log(); +console.log(<>); +console.log(); +console.log(<>); +console.log(); From ef9bbc4880dac83680374967484ae97a0260c719 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Wed, 2 Oct 2024 06:59:48 +0200 Subject: [PATCH 60/62] Fix local browser build --- browser/src/path.ts | 4 ++++ docs/.vitepress/config.ts | 4 ++++ docs/.vitepress/replace-path-picomatch.ts | 22 ++++++++++++++++++++++ docs/repl/stores/rollup.ts | 1 + 4 files changed, 31 insertions(+) create mode 100644 docs/.vitepress/replace-path-picomatch.ts diff --git a/browser/src/path.ts b/browser/src/path.ts index bc72123e1a8..65b1d4a1284 100644 --- a/browser/src/path.ts +++ b/browser/src/path.ts @@ -85,3 +85,7 @@ export function resolve(...paths: string[]): string { return resolvedParts.join('/'); } + +// Used for running the browser build locally in Vite +export const win32 = {}; +export const posix = {}; diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index f9b8e1f00b3..a4ddaef6a55 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -7,6 +7,7 @@ import replaceBrowserModules from '../../build-plugins/replace-browser-modules'; import '../declarations.d'; import { examplesPlugin } from './create-examples'; import { renderMermaidGraphsPlugin } from './mermaid'; +import { replacePathPicomatch } from './replace-path-picomatch'; import { transposeTables } from './transpose-tables'; import { buildEnd, callback, transformPageData } from './verify-anchors'; @@ -157,7 +158,10 @@ export default defineConfig({ title: 'Rollup', transformPageData, vite: { + optimizeDeps: { exclude: ['@rollup/pluginutils'] }, plugins: [ + replacePathPicomatch(), + replaceBrowserModules(), renderMermaidGraphsPlugin(), replaceBrowserModules(), { diff --git a/docs/.vitepress/replace-path-picomatch.ts b/docs/.vitepress/replace-path-picomatch.ts new file mode 100644 index 00000000000..16cd7871ba7 --- /dev/null +++ b/docs/.vitepress/replace-path-picomatch.ts @@ -0,0 +1,22 @@ +import path from 'path'; +import type { Plugin } from 'vite'; + +export function replacePathPicomatch(): Plugin { + return { + enforce: 'pre', + load(id) { + if (id === 'picomatch') { + return 'export default {}'; + } + }, + name: 'replace-picomatch', + resolveId(source) { + if (source === 'picomatch') { + return { id: 'picomatch' }; + } + if (source === 'path') { + return path.resolve(__dirname, '../../browser/src/path.ts'); + } + } + }; +} diff --git a/docs/repl/stores/rollup.ts b/docs/repl/stores/rollup.ts index e79140a329d..fb2d84df2d7 100644 --- a/docs/repl/stores/rollup.ts +++ b/docs/repl/stores/rollup.ts @@ -117,6 +117,7 @@ export const useRollup = defineStore('rollup', () => { instance }; } catch (error) { + console.error(error); loaded.value = { error: error as Error, instance: null From 4b2e94bc92340b61b3ab5895668d3896213e24a1 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Wed, 2 Oct 2024 07:25:11 +0200 Subject: [PATCH 61/62] Add jsx example --- docs/repl/examples/07/example.json | 14 +++++++------- docs/repl/examples/08/example.json | 8 ++++++++ docs/repl/examples/08/modules/main.js | 6 ++++++ docs/repl/examples/08/modules/other.js | 2 ++ 4 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 docs/repl/examples/08/example.json create mode 100644 docs/repl/examples/08/modules/main.js create mode 100644 docs/repl/examples/08/modules/other.js diff --git a/docs/repl/examples/07/example.json b/docs/repl/examples/07/example.json index 7dd6f889f9d..2e559572a75 100644 --- a/docs/repl/examples/07/example.json +++ b/docs/repl/examples/07/example.json @@ -1,10 +1,10 @@ { "title": "Multiple Entry Modules", - "entryModules": ["main.js", "otherEntry.js"], - "options": { - "output": { - "minifyInternalExports": false, - "preserveModules": false - } - } + "entryModules": ["main.js", "otherEntry.js"], + "options": { + "output": { + "minifyInternalExports": false, + "preserveModules": false + } + } } diff --git a/docs/repl/examples/08/example.json b/docs/repl/examples/08/example.json new file mode 100644 index 00000000000..f085d76c5cd --- /dev/null +++ b/docs/repl/examples/08/example.json @@ -0,0 +1,8 @@ +{ + "title": "JSX", + "options": { + "jsx": { + "mode": "preserve" + } + } +} diff --git a/docs/repl/examples/08/modules/main.js b/docs/repl/examples/08/modules/main.js new file mode 100644 index 00000000000..e9744cbb67b --- /dev/null +++ b/docs/repl/examples/08/modules/main.js @@ -0,0 +1,6 @@ +// JSX SUPPORT +// Try different jsx.mode and see how it is transformed +import './other.js'; +const Foo = ({ world }) =>
Hello {world}!
; + +console.log(); diff --git a/docs/repl/examples/08/modules/other.js b/docs/repl/examples/08/modules/other.js new file mode 100644 index 00000000000..724d561c110 --- /dev/null +++ b/docs/repl/examples/08/modules/other.js @@ -0,0 +1,2 @@ +const Foo = () =>
This is deconflicted!
; +console.log(); From 98f5c5a5a3f5762fa77d0f542af6adf8a03ee5a0 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Wed, 2 Oct 2024 09:10:27 +0200 Subject: [PATCH 62/62] Refine docs --- docs/configuration-options/index.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/configuration-options/index.md b/docs/configuration-options/index.md index 4a850a4c743..16adb70d3ba 100755 --- a/docs/configuration-options/index.md +++ b/docs/configuration-options/index.md @@ -206,7 +206,7 @@ type JsxOptions = Allows Rollup to process JSX syntax to either preserve or transform it depending on the [`jsx.mode`](#jsx-mode). If set to `false`, an error will be thrown if JSX syntax is encountered. You may also choose a preset that will set all options together: -- `"react"`: For transpiling JSX to `React.createElement` calls, where `React` is the default import from `"react"`. This is the same as setting `"jsx": "react"` in the TypeScript compiler options. +- `"react"`: For transpiling JSX to `React.createElement` calls, where `React` is the default import from `"react"`. This is similar to setting `"jsx": "react"` in TypeScript compiler options. ```js ({ mode: 'classic', @@ -215,7 +215,7 @@ Allows Rollup to process JSX syntax to either preserve or transform it depending importSource: 'react' }); ``` -- `"react-jsx"`: This will use the new optimized React transformation introduced with React 17 and is similar to setting `"jsx": "react-jsx"` in the TypeScript compiler options. +- `"react-jsx"`: This will use the new optimized React transformation introduced with React 17 and is similar to setting `"jsx": "react-jsx"` in TypeScript compiler options. ```js ({ mode: 'automatic', @@ -233,7 +233,7 @@ Allows Rollup to process JSX syntax to either preserve or transform it depending importSource: null }); ``` -- `"preserve-react"`: This will preserve JSX in the output but ensure that the default export of `"react"` is in scope as the `React` variable. +- `"preserve-react"`: This will preserve JSX in the output but ensure that the default export of `"react"` is in scope as a variable named `React`. ```js ({ mode: 'preserve', @@ -276,7 +276,7 @@ This will determine how JSX is processed: console.log(/*#__PURE__*/ h('div', null, 'hello')); ``` -- `"automatic"`: This will perform a JSX transformation using the [new JSX transform](https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) introduced with React 17. In this mode, Rollup will try to use helpers from the [`jsx.jsxImportSource`](#jsx-jsximportsource) to transform JSX. As there are certain edge cases, this mode may still fall back to using the classic transformations when [using the `key` property together with spread attributes](https://github.com/facebook/react/issues/20031#issuecomment-710346866). To this end, you can still specify `jsx.importSource`, `jsx.factory`, and `jsx.fragment` to configure classic mode. +- `"automatic"`: This will perform a JSX transformation using the [new JSX transform](https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) introduced with React 17. In this mode, Rollup will try to import helpers from [`jsx.jsxImportSource`](#jsx-jsximportsource) to transform JSX. As there are certain edge cases, this mode may still fall back to using the classic transformations when [using the `key` property together with spread attributes](https://github.com/facebook/react/issues/20031#issuecomment-710346866). To this end, you can still specify `jsx.importSource`, `jsx.factory`, and `jsx.fragment` to configure classic mode. #### jsx.factory @@ -286,7 +286,7 @@ This will determine how JSX is processed: | CLI: | `--jsx.factory ` | | Default: | `"React.createElement"` or `null` | -The function Rollup uses to create JSX elements in `"classic"` mode or as a fallback in `"automatic"` mode. This is usually `React.createElement` for React or `h` for other frameworks. In `"preserve"` mode, this will ensure that the factory is present if a [`jsx.importSource`](#jsx-importsource) is specified, or otherwise not overridden by local variables. Only in `"preserve"` mode it is possible to set this value to `null`, in which case Rollup will not take care to keep any particular factory function in scope. +The function Rollup uses to create JSX elements in `"classic"` mode or as a fallback in `"automatic"` mode. This is usually `React.createElement` for React or `h` for other frameworks. In `"preserve"` mode, this will ensure that the factory is in scope if [`jsx.importSource`](#jsx-importsource) is specified, or otherwise that a global variable of the same name would not be overridden by local variables. Only in `"preserve"` mode it is possible to set this value to `null`, in which case Rollup will not take care to keep any particular factory function in scope. If the value contains a `"."` like `React.createElement` and an `jsx.importSource` is specified, Rollup will assume that the left part, e.g. `React`, refers to the default export of the `jsx.importSource`. Otherwise, Rollup assumes it is a named export. @@ -298,7 +298,7 @@ If the value contains a `"."` like `React.createElement` and an `jsx.importSourc | CLI: | `--jsx.fragment ` | | Default: | `"React.Fragment"` or `null` | -The element function Rollup uses to create JSX fragments. This is usually `React.Fragment` for React or `Fragment` for other frameworks. In `"preserve"` mode, this will ensure that the fragment is present as an import if an [`jsx.importSource`](#jsx-importsource) is specified, or otherwise not overridden by local variables. Only in `"preserve"` mode it is possible to set this value to `null`, in which case Rollup will not take care to keep any particular fragment function in scope. +The element function Rollup uses to create JSX fragments. This is usually `React.Fragment` for React or `Fragment` for other frameworks. In `"preserve"` mode, this will ensure that the fragment is in scope if [`jsx.importSource`](#jsx-importsource) is specified, or otherwise that a global variable of the same name would not be overridden by local variables. Only in `"preserve"` mode it is possible to set this value to `null`, in which case Rollup will not take care to keep any particular fragment function in scope. If the value contains a `"."` like `React.Fragment` and an `jsx.importSource` is specified, Rollup will assume that the left part, e.g. `React`, refers to the default export of the `jsx.importSource`. Otherwise, Rollup assumes it is a named export. @@ -310,7 +310,7 @@ If the value contains a `"."` like `React.Fragment` and an `jsx.importSource` is | CLI: | `--jsx.importSource ` | | Default: | `null` | -Where to import the element factory function and/or the fragment element from. If left to `null`, Rollup will assume that `factory` and `fragment` refer to global variables and make sure they are not shadowed by local variables. +Where to import the element factory function and/or the fragment element from. If left to `null`, Rollup will assume that [`jsx.factory`](#jsx-factory) and [`jsx.fragment`](#jsx-fragment) refer to global variables and makes sure they are not shadowed by local variables. #### jsx.jsxImportSource