134 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| import CJSImportProcessor from "./CJSImportProcessor";
 | |
| import computeSourceMap, {} from "./computeSourceMap";
 | |
| import {HelperManager} from "./HelperManager";
 | |
| import identifyShadowedGlobals from "./identifyShadowedGlobals";
 | |
| import NameManager from "./NameManager";
 | |
| import {validateOptions} from "./Options";
 | |
| 
 | |
| import {parse} from "./parser";
 | |
| 
 | |
| import TokenProcessor from "./TokenProcessor";
 | |
| import RootTransformer from "./transformers/RootTransformer";
 | |
| import formatTokens from "./util/formatTokens";
 | |
| import getTSImportedNames from "./util/getTSImportedNames";
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| ;
 | |
| 
 | |
| export function getVersion() {
 | |
|   /* istanbul ignore next */
 | |
|   return "3.35.0";
 | |
| }
 | |
| 
 | |
| export function transform(code, options) {
 | |
|   validateOptions(options);
 | |
|   try {
 | |
|     const sucraseContext = getSucraseContext(code, options);
 | |
|     const transformer = new RootTransformer(
 | |
|       sucraseContext,
 | |
|       options.transforms,
 | |
|       Boolean(options.enableLegacyBabel5ModuleInterop),
 | |
|       options,
 | |
|     );
 | |
|     const transformerResult = transformer.transform();
 | |
|     let result = {code: transformerResult.code};
 | |
|     if (options.sourceMapOptions) {
 | |
|       if (!options.filePath) {
 | |
|         throw new Error("filePath must be specified when generating a source map.");
 | |
|       }
 | |
|       result = {
 | |
|         ...result,
 | |
|         sourceMap: computeSourceMap(
 | |
|           transformerResult,
 | |
|           options.filePath,
 | |
|           options.sourceMapOptions,
 | |
|           code,
 | |
|           sucraseContext.tokenProcessor.tokens,
 | |
|         ),
 | |
|       };
 | |
|     }
 | |
|     return result;
 | |
|     // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | |
|   } catch (e) {
 | |
|     if (options.filePath) {
 | |
|       e.message = `Error transforming ${options.filePath}: ${e.message}`;
 | |
|     }
 | |
|     throw e;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Return a string representation of the sucrase tokens, mostly useful for
 | |
|  * diagnostic purposes.
 | |
|  */
 | |
| export function getFormattedTokens(code, options) {
 | |
|   const tokens = getSucraseContext(code, options).tokenProcessor.tokens;
 | |
|   return formatTokens(code, tokens);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Call into the parser/tokenizer and do some further preprocessing:
 | |
|  * - Come up with a set of used names so that we can assign new names.
 | |
|  * - Preprocess all import/export statements so we know which globals we are interested in.
 | |
|  * - Compute situations where any of those globals are shadowed.
 | |
|  *
 | |
|  * In the future, some of these preprocessing steps can be skipped based on what actual work is
 | |
|  * being done.
 | |
|  */
 | |
| function getSucraseContext(code, options) {
 | |
|   const isJSXEnabled = options.transforms.includes("jsx");
 | |
|   const isTypeScriptEnabled = options.transforms.includes("typescript");
 | |
|   const isFlowEnabled = options.transforms.includes("flow");
 | |
|   const disableESTransforms = options.disableESTransforms === true;
 | |
|   const file = parse(code, isJSXEnabled, isTypeScriptEnabled, isFlowEnabled);
 | |
|   const tokens = file.tokens;
 | |
|   const scopes = file.scopes;
 | |
| 
 | |
|   const nameManager = new NameManager(code, tokens);
 | |
|   const helperManager = new HelperManager(nameManager);
 | |
|   const tokenProcessor = new TokenProcessor(
 | |
|     code,
 | |
|     tokens,
 | |
|     isFlowEnabled,
 | |
|     disableESTransforms,
 | |
|     helperManager,
 | |
|   );
 | |
|   const enableLegacyTypeScriptModuleInterop = Boolean(options.enableLegacyTypeScriptModuleInterop);
 | |
| 
 | |
|   let importProcessor = null;
 | |
|   if (options.transforms.includes("imports")) {
 | |
|     importProcessor = new CJSImportProcessor(
 | |
|       nameManager,
 | |
|       tokenProcessor,
 | |
|       enableLegacyTypeScriptModuleInterop,
 | |
|       options,
 | |
|       options.transforms.includes("typescript"),
 | |
|       Boolean(options.keepUnusedImports),
 | |
|       helperManager,
 | |
|     );
 | |
|     importProcessor.preprocessTokens();
 | |
|     // We need to mark shadowed globals after processing imports so we know that the globals are,
 | |
|     // but before type-only import pruning, since that relies on shadowing information.
 | |
|     identifyShadowedGlobals(tokenProcessor, scopes, importProcessor.getGlobalNames());
 | |
|     if (options.transforms.includes("typescript") && !options.keepUnusedImports) {
 | |
|       importProcessor.pruneTypeOnlyImports();
 | |
|     }
 | |
|   } else if (options.transforms.includes("typescript") && !options.keepUnusedImports) {
 | |
|     // Shadowed global detection is needed for TS implicit elision of imported names.
 | |
|     identifyShadowedGlobals(tokenProcessor, scopes, getTSImportedNames(tokenProcessor));
 | |
|   }
 | |
|   return {tokenProcessor, scopes, nameManager, importProcessor, helperManager};
 | |
| }
 |