sucrase
Version:
Super-fast alternative to Babel for when you can target modern JS runtimes
107 lines (106 loc) • 4.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const sucrase_babylon_1 = require("../sucrase-babylon");
const JSXTransformer_1 = require("./transformers/JSXTransformer");
const TokenProcessor_1 = require("./TokenProcessor");
const ImportTransformer_1 = require("./transformers/ImportTransformer");
const augmentTokenContext_1 = require("./augmentTokenContext");
const ImportProcessor_1 = require("./ImportProcessor");
const NameManager_1 = require("./NameManager");
const ReactDisplayNameTransformer_1 = require("./transformers/ReactDisplayNameTransformer");
const DEFAULT_BABYLON_PLUGINS = ['jsx', 'objectRestSpread'];
function transform(code, options = {}) {
const babylonPlugins = options.babylonPlugins || DEFAULT_BABYLON_PLUGINS;
const transforms = options.transforms || ['jsx'];
let tokens = sucrase_babylon_1.getTokens(code, { tokens: true, sourceType: 'module', plugins: babylonPlugins });
tokens = tokens.filter((token) => token.type !== 'CommentLine' && token.type !== 'CommentBlock');
augmentTokenContext_1.default(tokens);
const tokenProcessor = new TokenProcessor_1.default(code, tokens);
return new RootTransformer(tokenProcessor, transforms).transform();
}
exports.transform = transform;
class RootTransformer {
constructor(tokens, transforms) {
this.tokens = tokens;
this.transformers = [];
const nameManager = new NameManager_1.NameManager(tokens);
const importProcessor = transforms.includes('imports')
? new ImportProcessor_1.ImportProcessor(nameManager, tokens)
: null;
const identifierReplacer = importProcessor
? importProcessor
: { getIdentifierReplacement: () => null };
if (transforms.includes('jsx')) {
this.transformers.push(new JSXTransformer_1.default(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_1.default(this, tokens, identifierReplacer));
}
if (transforms.includes('imports')) {
const shouldAddModuleExports = transforms.includes('add-module-exports');
this.transformers.push(new ImportTransformer_1.default(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();
}
}
exports.RootTransformer = RootTransformer;