@@ -989,4 +989,63 @@ describe("JavascriptParser", () => {
989989 } ) ;
990990 }
991991 } ) ;
992+
993+ describe ( "new import call (acorn-import-phases)" , ( ) => {
994+ beforeAll ( ( ) => {
995+ const parser =
996+ /** @type {typeof JavascriptParser & { __importPhasesExtended?: true } } */
997+ ( JavascriptParser ) ;
998+ if ( ! parser . __importPhasesExtended ) {
999+ JavascriptParser . extend (
1000+ require ( "acorn-import-phases" ) ( { source : true , defer : true } )
1001+ ) ;
1002+ parser . __importPhasesExtended = true ;
1003+ }
1004+ } ) ;
1005+
1006+ /**
1007+ * @param {string } source source
1008+ * @returns {Error | null } thrown error, if any
1009+ */
1010+ function parse ( source ) {
1011+ try {
1012+ new JavascriptParser ( ) . parse (
1013+ source ,
1014+ /** @type {import("../lib/Parser").ParserState } */ (
1015+ /** @type {unknown } */ ( { source } )
1016+ )
1017+ ) ;
1018+ return null ;
1019+ } catch ( err ) {
1020+ return /** @type {Error } */ ( err ) ;
1021+ }
1022+ }
1023+
1024+ // `import.defer(...)`/`import.source(...)` are CallExpressions, so they
1025+ // cannot be the operand of `new`, including with member access (#21212).
1026+ for ( const source of [
1027+ 'new import.defer("x");' ,
1028+ 'new import.defer("x").prop;' ,
1029+ 'new import.defer("x").a.b;' ,
1030+ 'new import.source("x").prop;'
1031+ ] ) {
1032+ it ( `rejects ${ JSON . stringify ( source ) } ` , ( ) => {
1033+ const err = parse ( source ) ;
1034+ expect ( err ) . toBeInstanceOf ( SyntaxError ) ;
1035+ expect ( /** @type {Error } */ ( err ) . message ) . toBe (
1036+ "import call cannot be the target of `new`"
1037+ ) ;
1038+ } ) ;
1039+ }
1040+
1041+ // Parenthesized forms and non-`new` member access stay valid.
1042+ for ( const source of [
1043+ 'new (import.defer("x")).prop;' ,
1044+ 'import.defer("x").then(() => {});'
1045+ ] ) {
1046+ it ( `accepts ${ JSON . stringify ( source ) } ` , ( ) => {
1047+ expect ( parse ( source ) ) . toBeNull ( ) ;
1048+ } ) ;
1049+ }
1050+ } ) ;
9921051} ) ;
0 commit comments