- Add npm scripts for CSS/JS compilation (build:css, build:js, build) - Create PowerShell build automation script - Document development workflow in README - Add troubleshooting guide for build issues - Specify proper file structure and compilation process Supports Tailwind CSS v3.4.0 and esbuild bundling with source maps.
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};
|
|
}
|