UNPKG

sucrase

Version:

Super-fast alternative to Babel for when you can target modern JS runtimes

103 lines (102 loc) 4.15 kB
import { getTokens } from '../sucrase-babylon'; import JSXTransformer from './transformers/JSXTransformer'; import TokenProcessor from './TokenProcessor'; import ImportTransformer from './transformers/ImportTransformer'; import augmentTokenContext from './augmentTokenContext'; import { ImportProcessor } from './ImportProcessor'; import { NameManager } from './NameManager'; import ReactDisplayNameTransformer from './transformers/ReactDisplayNameTransformer'; const DEFAULT_BABYLON_PLUGINS = ['jsx', 'objectRestSpread']; export function transform(code, options = {}) { const babylonPlugins = options.babylonPlugins || DEFAULT_BABYLON_PLUGINS; const transforms = options.transforms || ['jsx']; let tokens = getTokens(code, { tokens: true, sourceType: 'module', plugins: babylonPlugins }); tokens = tokens.filter((token) => token.type !== 'CommentLine' && token.type !== 'CommentBlock'); augmentTokenContext(tokens); const tokenProcessor = new TokenProcessor(code, tokens); return new RootTransformer(tokenProcessor, transforms).transform(); } export class RootTransformer { constructor(tokens, transforms) { this.tokens = tokens; this.transformers = []; const nameManager = new NameManager(tokens); const importProcessor = transforms.includes('imports') ? new ImportProcessor(nameManager, tokens) : null; const identifierReplacer = importProcessor ? importProcessor : { getIdentifierReplacement: () => null }; if (transforms.includes('jsx')) { this.transformers.push(new JSXTransformer(this, tokens, identifierReplacer)); } // react-display-name must come before imports since otherwise imports will // claim a normal `React` name token. if (transforms.includes('react-display-name')) { this.transformers.push(new ReactDisplayNameTransformer(this, tokens, identifierReplacer)); } if (transforms.includes('imports')) { const shouldAddModuleExports = transforms.includes('add-module-exports'); this.transformers.push(new ImportTransformer(this, tokens, nameManager, importProcessor, shouldAddModuleExports)); } } transform() { this.tokens.reset(); for (const transformer of this.transformers) { transformer.preprocess(); } this.processBalancedCode(); let prefix = ''; for (const transformer of this.transformers) { prefix += transformer.getPrefixCode(); } let suffix = ''; for (const transformer of this.transformers) { suffix += transformer.getSuffixCode(); } return prefix + this.tokens.finish() + suffix; } processBalancedCode() { let braceDepth = 0; let parenDepth = 0; while (!this.tokens.isAtEnd()) { let wasProcessed = false; for (const transformer of this.transformers) { wasProcessed = transformer.process(); if (wasProcessed) { break; } } if (!wasProcessed) { if (this.tokens.matches(['{']) || this.tokens.matches(['${'])) { braceDepth++; } else if (this.tokens.matches(['}'])) { if (braceDepth === 0) { return; } braceDepth--; } if (this.tokens.matches(['('])) { parenDepth++; } else if (this.tokens.matches([')'])) { if (parenDepth === 0) { return; } parenDepth--; } this.tokens.copyToken(); } } } processToken() { for (const transformer of this.transformers) { const wasProcessed = transformer.process(); if (wasProcessed) { return; } } this.tokens.copyToken(); } }