You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||
|  | 	Author Tobias Koppers @sokra | ||
|  | */ | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | 
 | ||
|  | const { JAVASCRIPT_MODULE_TYPE_ESM } = require("../ModuleTypeConstants"); | ||
|  | const DynamicExports = require("./DynamicExports"); | ||
|  | const HarmonyCompatibilityDependency = require("./HarmonyCompatibilityDependency"); | ||
|  | const HarmonyExports = require("./HarmonyExports"); | ||
|  | 
 | ||
|  | /** @typedef {import("../Module").BuildMeta} BuildMeta */ | ||
|  | /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ | ||
|  | /** @typedef {import("./HarmonyModulesPlugin").HarmonyModulesPluginOptions} HarmonyModulesPluginOptions */ | ||
|  | 
 | ||
|  | module.exports = class HarmonyDetectionParserPlugin { | ||
|  | 	/** | ||
|  | 	 * @param {HarmonyModulesPluginOptions} options options | ||
|  | 	 */ | ||
|  | 	constructor(options) { | ||
|  | 		const { topLevelAwait = false } = options || {}; | ||
|  | 		this.topLevelAwait = topLevelAwait; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {JavascriptParser} parser the parser | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	apply(parser) { | ||
|  | 		parser.hooks.program.tap("HarmonyDetectionParserPlugin", ast => { | ||
|  | 			const isStrictHarmony = | ||
|  | 				parser.state.module.type === JAVASCRIPT_MODULE_TYPE_ESM; | ||
|  | 			const isHarmony = | ||
|  | 				isStrictHarmony || | ||
|  | 				ast.body.some( | ||
|  | 					statement => | ||
|  | 						statement.type === "ImportDeclaration" || | ||
|  | 						statement.type === "ExportDefaultDeclaration" || | ||
|  | 						statement.type === "ExportNamedDeclaration" || | ||
|  | 						statement.type === "ExportAllDeclaration" | ||
|  | 				); | ||
|  | 			if (isHarmony) { | ||
|  | 				const module = parser.state.module; | ||
|  | 				const compatDep = new HarmonyCompatibilityDependency(); | ||
|  | 				compatDep.loc = { | ||
|  | 					start: { | ||
|  | 						line: -1, | ||
|  | 						column: 0 | ||
|  | 					}, | ||
|  | 					end: { | ||
|  | 						line: -1, | ||
|  | 						column: 0 | ||
|  | 					}, | ||
|  | 					index: -3 | ||
|  | 				}; | ||
|  | 				module.addPresentationalDependency(compatDep); | ||
|  | 				DynamicExports.bailout(parser.state); | ||
|  | 				HarmonyExports.enable(parser.state, isStrictHarmony); | ||
|  | 				parser.scope.isStrict = true; | ||
|  | 			} | ||
|  | 		}); | ||
|  | 
 | ||
|  | 		parser.hooks.topLevelAwait.tap("HarmonyDetectionParserPlugin", () => { | ||
|  | 			const module = parser.state.module; | ||
|  | 			if (!this.topLevelAwait) { | ||
|  | 				throw new Error( | ||
|  | 					"The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it)" | ||
|  | 				); | ||
|  | 			} | ||
|  | 			if (!HarmonyExports.isEnabled(parser.state)) { | ||
|  | 				throw new Error( | ||
|  | 					"Top-level-await is only supported in EcmaScript Modules" | ||
|  | 				); | ||
|  | 			} | ||
|  | 			/** @type {BuildMeta} */ | ||
|  | 			(module.buildMeta).async = true; | ||
|  | 		}); | ||
|  | 
 | ||
|  | 		/** | ||
|  | 		 * @returns {boolean | undefined} true if in harmony | ||
|  | 		 */ | ||
|  | 		const skipInHarmony = () => { | ||
|  | 			if (HarmonyExports.isEnabled(parser.state)) { | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		/** | ||
|  | 		 * @returns {null | undefined} null if in harmony | ||
|  | 		 */ | ||
|  | 		const nullInHarmony = () => { | ||
|  | 			if (HarmonyExports.isEnabled(parser.state)) { | ||
|  | 				return null; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		const nonHarmonyIdentifiers = ["define", "exports"]; | ||
|  | 		for (const identifier of nonHarmonyIdentifiers) { | ||
|  | 			parser.hooks.evaluateTypeof | ||
|  | 				.for(identifier) | ||
|  | 				.tap("HarmonyDetectionParserPlugin", nullInHarmony); | ||
|  | 			parser.hooks.typeof | ||
|  | 				.for(identifier) | ||
|  | 				.tap("HarmonyDetectionParserPlugin", skipInHarmony); | ||
|  | 			parser.hooks.evaluate | ||
|  | 				.for(identifier) | ||
|  | 				.tap("HarmonyDetectionParserPlugin", nullInHarmony); | ||
|  | 			parser.hooks.expression | ||
|  | 				.for(identifier) | ||
|  | 				.tap("HarmonyDetectionParserPlugin", skipInHarmony); | ||
|  | 			parser.hooks.call | ||
|  | 				.for(identifier) | ||
|  | 				.tap("HarmonyDetectionParserPlugin", skipInHarmony); | ||
|  | 		} | ||
|  | 	} | ||
|  | }; |