134 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
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};
 | 
						|
}
 |