@babel/core#NodePath TypeScript Examples
The following examples show how to use
@babel/core#NodePath.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: separateVariableDeclarations.ts From vidact with MIT License | 6 votes |
export function separateVariableDeclarations(fnPath: NodePath) {
fnPath.traverse({
VariableDeclaration(path) {
const declarations = path.get("declarations");
if (declarations.length < 2) {
return;
}
path.replaceWithMultiple(
declarations.map(declaration =>
t.variableDeclaration(path.get("kind"), [declaration.node])
)
);
}
});
}
Example #2
Source File: typecheck.macro.ts From typecheck.macro with MIT License | 6 votes |
function finalizeType(
path: NodePath<t.Node>,
instantiatedTypes: Map<string, TypeInfo>,
namedTypes: Map<string, IR>
): [IR, Map<string, number>] {
const typeParam = getTypeParameter(path);
let ir = getTypeParameterIR(typeParam.node);
const state: InstantiationStatePartial = {
instantiatedTypes,
namedTypes,
typeStats: new Map(),
newInstantiatedTypes: [],
};
// no type resolution on the type parameter
ir = flattenType(ir);
const instantiatedIR = instantiateIR(ir, state);
for (const type of state.newInstantiatedTypes) {
const newType = instantiatedTypes.get(type);
if (newType === undefined) {
throwUnexpectedError(`did not expected ${type} to be undefined`);
}
newType.value = cleanUnions(
solveIntersections(newType.value, instantiatedTypes),
instantiatedTypes
);
instantiatedTypes.set(type, newType);
}
const finalIR = cleanUnions(
solveIntersections(instantiatedIR, instantiatedTypes),
instantiatedTypes
);
return [finalIR, state.typeStats];
}
Example #3
Source File: declarationToAssignment.ts From vidact with MIT License | 6 votes |
export function declarationToAssignment(path: NodePath<t.VariableDeclaration>) {
const declarator = path.get("declarations")[0];
const { id, init } = declarator.node;
path.replaceWith(
t.expressionStatement(
t.assignmentExpression("=", id, init || t.identifier("undefined"))
)
);
let ids: string[];
if (t.isIdentifier(id)) {
ids = [id.name];
} else {
declarator.get("id").traverse(
{
Identifier(idPath, state) {
const { name } = idPath.node;
if (!state.includes(name)) {
state.push(name);
}
}
},
(ids = [])
);
}
return ids;
}
Example #4
Source File: macro-assertions.ts From typecheck.macro with MIT License | 6 votes |
export function getTypeParameter(
macroPath: NodePath<t.Node>
): NodePath<t.TSType> {
const callExpr = macroPath.parentPath;
assertCallExpr(callExpr);
const typeParametersPath = callExpr.get("typeParameters");
if (
typeParametersPath &&
!Array.isArray(typeParametersPath) &&
typeParametersPath.node
) {
const { node } = typeParametersPath;
if (t.isTSTypeParameterInstantiation(node)) {
const params = node.params.length;
if (params != 1)
throw new MacroError(Errors.MoreThanOneTypeParameter(params));
const typeParameterPath = typeParametersPath.get("params.0");
if (
!Array.isArray(typeParameterPath) &&
// @ts-ignore: https://github.com/babel/babel/issues/11535
typeParameterPath.isTSType()
) {
// @ts-ignore: https://github.com/babel/babel/issues/11535
return typeParameterPath;
}
throwUnexpectedError(
`typeParameter was ${
Array.isArray(typeParameterPath) ? "an array" : "not a TSType"
}`
);
}
throwUnexpectedError(
`typeParameters node was ${node.type} instead of TSTypeParameterInstantiation`
);
} else {
throw new MacroError(Errors.NoTypeParameters());
}
}
Example #5
Source File: scanDeepDependencies.ts From vidact with MIT License | 6 votes |
function extractNames(path: NodePath<t.VariableDeclaration>): string[] {
const { id } = path.node.declarations[0];
if (t.isIdentifier(id)) {
return [id.name];
} else if (t.isArrayPattern(id)) {
return (id.elements as t.Identifier[]).map(({ name }) => name);
}
return [];
}
Example #6
Source File: macro-assertions.ts From typecheck.macro with MIT License | 6 votes |
export function getBlockParent(macroPath: NodePath<t.Node>): t.Statement[] {
const callExpr = macroPath.parentPath;
assertCallExpr(callExpr);
const exprStmt = callExpr.parentPath;
if (!exprStmt.isExpressionStatement())
throw new MacroError(Errors.InvalidRegisterCall());
const { node } = exprStmt.parentPath;
if (!t.isProgram(node) && !t.isBlock(node)) {
throw new MacroError(Errors.InvalidRegisterCall());
} else {
return node.body;
}
}
Example #7
Source File: plugin.ts From vite-react-jsx with MIT License | 6 votes |
/**
* Replace this:
*
* import { jsx as _jsx } from "react/jsx-runtime"
*
* with this:
*
* var _jsx = require("react/jsx-runtime").jsx
*/
export function babelImportToRequire({
types: t,
}: typeof import('@babel/core')) {
return {
visitor: {
ImportDeclaration(path: NodePath) {
const decl = path.node as ImportDeclaration
const spec = decl.specifiers[0] as ImportSpecifier
path.replaceWith(
t.variableDeclaration('var', [
t.variableDeclarator(
spec.local,
t.memberExpression(
t.callExpression(t.identifier('require'), [decl.source]),
spec.imported
)
),
])
)
},
},
}
}
Example #8
Source File: dump-helpers.ts From typecheck.macro with MIT License | 6 votes |
export function replaceWithCode(
code: string,
path: NodePath<t.Node>,
filename: string
): void {
const ast = parse(code, { filename });
if (t.isFile(ast)) {
path.replaceWith(ast.program.body[0]);
} else {
throwUnexpectedError(
`${code} was incorrectly parsed. The AST was: ${JSON.stringify(ast)}`
);
}
}
Example #9
Source File: createStateDefinition.ts From vidact with MIT License | 6 votes |
export function createStateDefinition(
state: ComponentState,
fnPath: NodePath<t.FunctionDeclaration>
) {
const states = state.state;
const internalStateDeclaration = t.variableDeclaration("const", [
t.variableDeclarator(
t.identifier(STATE_VAR),
t.objectExpression(
states.map(({ name, initialValue }) =>
t.objectProperty(name, initialValue || t.identifier("undefined"))
)
)
)
]);
const defineUpdater = t.variableDeclaration("const", [
t.variableDeclarator(
t.identifier(KEY_STATE_UPDATER),
createUpdatableUpdater(fnPath.get("body"), state, "state")
)
]);
return [internalStateDeclaration, defineUpdater];
}
Example #10
Source File: img.ts From react-optimized-image with MIT License | 6 votes |
transformImgComponent = (types: Babel['types'], path: NodePath<JSXElement>): void => {
// abort if it has already the rawSrc attribute
if (getAttribute(path, 'rawSrc')) {
return;
}
// get src attribute
const src = getAttribute(path, 'src');
const requireArgs = src ? getRequireArguments(types, src) : undefined;
if (!src || !requireArgs) {
return;
}
const config = buildConfig(types, path);
const query: Record<string, string> = {};
// add boolean queries
['inline', 'url', 'original'].forEach((attr) => {
if ((config as Record<string, unknown>)[attr] === true) {
query[attr] = '';
}
});
// transfer original src attribute if a new query param needs to be set
if (Object.keys(query).length > 0) {
(src.get('value') as NodePath).replaceWith(
types.jsxExpressionContainer(buildRequireStatement(types, clone(requireArgs), query)),
);
}
const rawSrc = buildRawSrcAttribute(types, requireArgs, config, query);
(path.get('openingElement') as NodePath<JSXOpeningElement>).pushContainer('attributes', rawSrc);
}
Example #11
Source File: getStatementUpdaterIdentifier.ts From vidact with MIT License | 6 votes |
export default function getStatementUpdaterIdentifier(
path: NodePath<t.VariableDeclaration>
): string {
const { node: id } = path.get("declarations")[0].get("id");
if (t.isIdentifier(id)) {
return id.name;
}
if (t.isArrayPattern(id) && t.isIdentifier(id.elements[0])) {
return id.elements[0].name;
}
throw new Error(
"Statement updater declarator must be an Identifier or ArrayPattern"
);
}
Example #12
Source File: traverse.ts From react-optimized-image with MIT License | 6 votes |
getRequireArguments = (
types: Babel['types'],
path: NodePath<JSXAttribute>,
): CallExpression['arguments'] | undefined => {
// check for inline-require statement
if (
path.node.value &&
path.node.value.type === 'JSXExpressionContainer' &&
path.node.value.expression.type === 'CallExpression' &&
path.node.value.expression.callee.type === 'Identifier' &&
path.node.value.expression.callee.name === 'require' &&
path.node.value.expression.arguments.length > 0
) {
return path.node.value.expression.arguments;
}
// check for import reference
if (
path.node.value &&
path.node.value.type === 'JSXExpressionContainer' &&
path.node.value.expression.type === 'Identifier'
) {
const variableName = path.node.value.expression.name;
const binding = path.scope.getBinding(variableName);
if (
binding &&
binding.kind === 'module' &&
isImport(binding.path) &&
binding.path.parent.type === 'ImportDeclaration'
) {
return [types.stringLiteral(binding.path.parent.source.value)];
}
}
}
Example #13
Source File: plugin.ts From telefunc with MIT License | 6 votes |
function isFileAlreadyTransformed(path: NodePath<BabelTypes.Program>, types: typeof BabelTypes): boolean {
return path.node.body.some((t) => {
if (!types.isImportDeclaration(t)) return false
if (t.specifiers.length === 0) return false
const specifier = t.specifiers[0]
if (!types.isImportSpecifier(specifier)) return false
if (!types.isImportSpecifier(specifier)) return false
if (!types.isIdentifier(specifier.imported)) return false
return specifier.imported.name === '__internal_fetchTelefunc'
})
}
Example #14
Source File: svg.ts From react-optimized-image with MIT License | 6 votes |
transformSvgComponent = (types: Babel['types'], path: NodePath<JSXElement>): void => {
// abort if it has already the rawSrc attribute
if (getAttribute(path, 'rawSrc')) {
return;
}
const src = getAttribute(path, 'src');
const requireArgs = src ? getRequireArguments(types, src) : undefined;
if (!src || !requireArgs) {
return;
}
const rawSrc = buildRawSrcAttribute(types, requireArgs);
(path.get('openingElement') as NodePath<JSXOpeningElement>).pushContainer('attributes', rawSrc);
src.remove();
}
Example #15
Source File: index.ts From glaze with MIT License | 6 votes |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function findNearestParentComponent(path: NodePath<any>): NodePath | undefined {
while (path) {
const { scope } = path;
const node = path.scope.path;
if (types.isExportDefaultDeclaration(scope.path.parent)) {
return node;
}
const functionIdentifier = getFunctionIdentifier(scope.path);
if (functionIdentifier) {
if (isComponent(functionIdentifier) || isHook(functionIdentifier)) {
return node;
}
}
path = scope.path.parentPath;
}
return undefined;
}
Example #16
Source File: jsx.ts From react-optimized-image with MIT License | 6 votes |
getBooleanAttribute = (path: NodePath<JSXElement>, attributeName: string): boolean | undefined => {
const attribute = getAttribute(path, attributeName);
if (attribute) {
if (attribute.node.value === null) {
return true;
}
if (
attribute.node.value.type === 'JSXExpressionContainer' &&
attribute.node.value.expression.type === 'BooleanLiteral'
) {
return attribute.node.value.expression.value;
}
// todo: better error message with link to docs when ready & create test for this error
throw attribute.get('value').buildCodeFrameError('Only static boolean values are allowed');
}
return undefined;
}
Example #17
Source File: index.ts From vanilla-extract with MIT License | 5 votes |
getDebugId = (path: NodePath<t.CallExpression>) => {
const firstRelevantParentPath = path.findParent(
({ node }) => !(t.isCallExpression(node) || t.isSequenceExpression(node)),
);
if (!firstRelevantParentPath) {
return;
}
// Special case: Handle `export const [themeClass, vars] = createTheme({});`
// when it's already been compiled into this:
//
// var _createTheme = createTheme({}),
// _createTheme2 = _slicedToArray(_createTheme, 2),
// themeClass = _createTheme2[0],
// vars = _createTheme2[1];
if (
t.isVariableDeclaration(firstRelevantParentPath.parent) &&
firstRelevantParentPath.parent.declarations.length === 4
) {
const [themeDeclarator, , classNameDeclarator] =
firstRelevantParentPath.parent.declarations;
if (
t.isCallExpression(themeDeclarator.init) &&
t.isIdentifier(themeDeclarator.init.callee, { name: 'createTheme' }) &&
t.isVariableDeclarator(classNameDeclarator) &&
t.isIdentifier(classNameDeclarator.id)
) {
return classNameDeclarator.id.name;
}
}
const relevantParent = firstRelevantParentPath.node;
if (
t.isObjectProperty(relevantParent) ||
t.isReturnStatement(relevantParent) ||
t.isArrowFunctionExpression(relevantParent) ||
t.isArrayExpression(relevantParent) ||
t.isSpreadElement(relevantParent)
) {
const names: Array<string> = [];
path.findParent(({ node }) => {
const name = extractName(node);
if (name) {
names.unshift(name);
}
// Traverse all the way to the root
return false;
});
return names.join('_');
} else {
return extractName(relevantParent);
}
}
Example #18
Source File: createUpdatableUpdater.ts From vidact with MIT License | 5 votes |
findCallee = (name: string) => (o: NodePath) => {
return isCallExpressionWithName(o.node, name);
}
Example #19
Source File: traverse.ts From react-optimized-image with MIT License | 5 votes |
isImport = (path: NodePath): boolean => {
return path.type === 'ImportSpecifier' || path.type === 'ImportDefaultSpecifier';
}
Example #20
Source File: macro-assertions.ts From typecheck.macro with MIT License | 5 votes |
function assertCallExpr(
expr: NodePath<t.Node>
): asserts expr is NodePath<t.Node> & NodePath<t.CallExpression> {
if (!expr.isCallExpression())
throw new MacroError(Errors.NotCalledAsFunction(expr.type));
}
Example #21
Source File: img.ts From react-optimized-image with MIT License | 5 votes |
buildConfig = (types: Babel['types'], path: NodePath<JSXElement>): ImageConfig => {
// build config
let config: ImageConfig = { ...(globalImageConfig.default || {}) };
// check if a specific type is set
const type = getTypeAttribute(path, Object.keys(globalImageConfig.types || {}));
// add type configs
if (type && globalImageConfig.types && globalImageConfig.types[type]) {
config = { ...config, ...globalImageConfig.types[type] };
}
// check boolean attributes: webp, inline, url, original
['webp', 'inline', 'url', 'original'].forEach((attr) => {
const value = getBooleanAttribute(path, attr);
if (typeof value !== 'undefined') {
(config as Record<string, unknown>)[attr] = value;
} else if (typeof value === 'undefined' && (config as Record<string, unknown>)[attr] === true) {
// add attr from global image config
(path.get('openingElement') as NodePath<JSXOpeningElement>).pushContainer(
'attributes',
types.jsxAttribute(types.jsxIdentifier(attr), null),
);
}
});
// get sizes
const sizes = getNumberedArrayAttribute(path, 'sizes');
if (typeof sizes !== 'undefined') {
config.sizes = sizes;
} else if (config.sizes) {
// add sizes attr from global image config
(path.get('openingElement') as NodePath<JSXOpeningElement>).pushContainer(
'attributes',
types.jsxAttribute(
types.jsxIdentifier('sizes'),
types.jsxExpressionContainer(types.arrayExpression(config.sizes.map((size) => types.numericLiteral(size)))),
),
);
}
// get densities
const densities = getNumberedArrayAttribute(path, 'densities');
if (typeof densities !== 'undefined') {
config.densities = densities;
} else if (config.densities) {
// add densities attr from global image config
(path.get('openingElement') as NodePath<JSXOpeningElement>).pushContainer(
'attributes',
types.jsxAttribute(
types.jsxIdentifier('densities'),
types.jsxExpressionContainer(types.arrayExpression(config.densities.map((size) => types.numericLiteral(size)))),
),
);
}
// get breakpoints
const breakpoints = getNumberedArrayAttribute(path, 'breakpoints');
if (typeof breakpoints !== 'undefined') {
config.breakpoints = breakpoints;
} else if (config.breakpoints) {
// add breakpoints attr from global image config
(path.get('openingElement') as NodePath<JSXOpeningElement>).pushContainer(
'attributes',
types.jsxAttribute(
types.jsxIdentifier('breakpoints'),
types.jsxExpressionContainer(
types.arrayExpression(config.breakpoints.map((size) => types.numericLiteral(size))),
),
),
);
}
return config;
}
Example #22
Source File: annotations.ts From vidact with MIT License | 5 votes |
export function annotate(path: NodePath, annotation: Annotation) {
path.addComment("leading", " @vidact-" + annotation, true);
}
Example #23
Source File: index.ts From design-systems-cli with MIT License | 5 votes |
/**
* Find imports of @design-system/cli components and automatically includes their styles.
*/
export default function includeStyles(
{ types }: Babel,
{ scope }: IncludeStylesOptions
): babel.PluginObj {
const SCOPE_REGEX = new RegExp(`^@${scope}\\/`);
let cssImports = new Set<string>();
/** Insert an import for a component */
function insertCssImports(
path: NodePath<BabelTypes.ImportDeclaration>,
importName: string
) {
if (!SCOPE_REGEX.test(importName)) {
return;
}
if (importName.match(/\.css$/)) {
// Only keep 1 import per imported css file
if (cssImports.has(importName)) {
path.remove();
} else {
cssImports.add(importName);
}
return;
}
const cssImport = `${importName}/dist/main.css`;
if (exists(cssImport)) {
path.insertAfter(
types.importDeclaration([], types.stringLiteral(cssImport))
);
}
// After walk dependencies to find more css to include
const packageJson = resolvePackage(importName)
if (!packageJson) {
return;
}
// After walk dependencies to find more css to include
// eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires
const { dependencies = {}, name } = require(packageJson);
// In case we happen to find a package.json that is for the specified scope
if (!SCOPE_REGEX.test(name)) {
return;
}
Object.keys(dependencies).forEach((dependency: string) =>
insertCssImports(path, dependency)
);
}
return {
/** Initialization code */
pre: () => {
cssImports = new Set<string>();
},
visitor: {
ImportDeclaration(path) {
const importName = path.node.source.value;
insertCssImports(path, importName);
}
}
};
}
Example #24
Source File: scanDeepDependencies.ts From vidact with MIT License | 5 votes |
function isUpdater(path: NodePath<t.VariableDeclaration>) {
const { id } = path.node.declarations[0];
return t.isIdentifier(id) &&
(isStatementExecuter(id.name) || isElementUpdate(id.name))
? id
: undefined;
}
Example #25
Source File: index.ts From design-systems-cli with MIT License | 5 votes |
/**
* Find imports of @design-system/cli components and optionally replaces their style imports.
*/
export default function replaceStyles(
{ types }: Babel,
{ scope, use, replace = 'main' }: ReplaceStylesOptions
): babel.PluginObj {
/** Replace an import inside a component */
function replaceCssImports(
path: NodePath<BabelTypes.ImportDeclaration>,
state: PluginPass,
importName: string
) {
const isScope =
state?.file?.opts?.filename &&
state.file.opts.filename.includes(`@${scope}/`);
if (isScope && importName.includes(`${replace}.css`)) {
// We found a candidate for replacement
const dirname = nodePath.dirname(state.file.opts.filename as string);
const next = nodePath.join(dirname, importName.replace(replace, use));
if (exists(next)) {
// Replacement exists
const importDeclaration = types.importDeclaration(
[],
types.stringLiteral(`../${use}.css`)
);
path.replaceInline(importDeclaration);
}
}
}
/** Replace an css.js import inside a component */
function replaceCssJsImports(
path: NodePath<BabelTypes.ImportDeclaration>,
state: PluginPass,
importName: string
) {
const isScope =
state?.file?.opts?.filename &&
state.file.opts.filename.includes(`@${scope}/`);
if (
isScope &&
path.node.specifiers.length &&
importName.includes('.css') &&
!importName.includes(use)
) {
const dirname = nodePath.dirname(state.file.opts.filename as string);
const newImport = importName.replace('.css', `-${use}.css`);
const newImportPath = nodePath.join(dirname, newImport);
if (exists(newImportPath)) {
const importDeclaration = types.importDeclaration(
path.node.specifiers,
types.stringLiteral(newImport)
);
path.replaceWith(importDeclaration);
}
}
}
return {
visitor: {
ImportDeclaration(path, state) {
const importName = path.node.source.value;
replaceCssImports(path, state, importName);
replaceCssJsImports(path, state, importName);
},
},
};
}
Example #26
Source File: index.ts From glaze with MIT License | 5 votes |
/* Source: https://github.com/facebook/react/blob/master/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js#L542 */
function getFunctionIdentifier(path: NodePath): types.Identifier | undefined {
const { node } = path;
const { parent } = path;
if (path.isFunctionDeclaration()) {
return path.node.id || undefined;
}
if (path.isFunctionExpression()) {
return path.node.id || undefined;
}
if (path.isFunctionExpression() || path.isArrowFunctionExpression()) {
if (
types.isVariableDeclarator(parent) &&
parent.init === node &&
types.isIdentifier(parent.id)
) {
return parent.id;
}
if (
types.isAssignmentExpression(parent) &&
parent.right === node &&
parent.operator === '=' &&
types.isIdentifier(parent.left)
) {
return parent.left;
}
if (
types.isProperty(parent) &&
parent.value === node &&
types.isIdentifier(parent.key)
) {
return parent.key;
}
if (
types.isAssignmentPattern(parent) &&
parent.right === node &&
types.isIdentifier(parent.left)
) {
return parent.left;
}
} else {
return undefined;
}
return undefined;
}
Example #27
Source File: normalizeUseMemo.ts From vidact with MIT License | 5 votes |
export function normalizeUseMemo(
path: NodePath<t.CallExpression>,
state: ComponentState
) {
if (!t.isIdentifier(path.node.callee)) {
return;
}
const calleeName = path.node.callee.name;
const isMemo = calleeName === USE_MEMO;
const isCallback = calleeName === USE_CALLBACK;
if (!isCallback && !isMemo) {
return;
}
const [memoizedValue, dependencies] = path.get("arguments");
if (!memoizedValue || !dependencies) {
throw path.buildCodeFrameError(`${calleeName} expects 2 arugments.`);
}
if (
!memoizedValue.isFunctionExpression() &&
!memoizedValue.isArrowFunctionExpression()
) {
throw path.buildCodeFrameError(
`The first argument of ${calleeName} must be a function expression.`
);
}
if (!dependencies.isArrayExpression()) {
throw path.buildCodeFrameError(
`The second argument of ${calleeName} must be an array of dependencies.`
);
}
const statement = path.getStatementParent();
annotate(statement, calleeName);
annotate(statement, "locked");
if (isMemo) {
path.replaceWith(t.callExpression(memoizedValue.node, []));
} else {
path.replaceWith(memoizedValue.node);
}
if (dependencies.get("elements").length === 0) {
return;
}
if (!statement.isVariableDeclaration()) {
throw statement.buildCodeFrameError(
`${calleeName} must be used with variable declaration`
);
}
const names = declarationToAssignment(statement);
names.forEach((name) => {
state.variablesWithDependencies.add(name);
state.variableStatementDependencyManager.push(
{ type: "local", name },
{ type: "node", value: statement }
);
});
const descriptors = addHookDependencyCheck(dependencies, memoizedValue);
descriptors.forEach((descriptor) => {
names.forEach((name) => {
state.variableStatementDependencyManager.push(descriptor, {
type: "local",
name,
});
});
});
}
Example #28
Source File: plugin.ts From telefunc with MIT License | 5 votes |
function getExportsFromBabelAST(programNodePath: NodePath<BabelTypes.Program>, types: typeof BabelTypes) {
const body = programNodePath.node.body
const exported = []
for (let index = 0; index < body.length; index++) {
const subNode = body[index]
// export default fnName
if (types.isExportDefaultDeclaration(subNode)) {
exported.push('default')
}
if (types.isExportNamedDeclaration(subNode)) {
if (subNode.specifiers.length > 0) {
// Handles cases:
// export { functionName };
// export { functionName as fnName };
// export { functionName as "fnName" };
// export { "fnName" } from "package";
for (const specifier of subNode.specifiers) {
if (specifier.exported.type === 'Identifier') {
// export { functionName };
// export { functionName as fnName };
exported.push(specifier.exported.name)
} else if (specifier.exported.type === 'StringLiteral') {
// export { functionName as "fnName" };
// export { "fnName" } from "package";
exported.push(specifier.exported.value)
}
}
} else if (types.isFunctionDeclaration(subNode.declaration)) {
// export function fn() {}
// export async function fn() {}
exported.push(subNode.declaration.id!.name) // Function must have ID if it's part of a named export
} else if (types.isVariableDeclaration(subNode.declaration)) {
// export const fnName = () => {}
// export var fnName = () => {}
// export let fnName = () => {}
// export const fnName = function() {}
// export var fnName = function() {}
// export let fnName = function() {}
const declarator = subNode.declaration.declarations[0]!
if (
'name' in declarator.id &&
(types.isFunctionExpression(declarator.init) || types.isArrowFunctionExpression(declarator.init))
) {
exported.push(declarator.id.name) // Function must have ID if it's part of a named export
}
}
}
}
return exported
}
Example #29
Source File: add-exports-array.ts From mpflow with MIT License | 4 votes |
/**
* 向配置文件如
* module.exports = { plugins: [] }
* 中的 plugins 添加插件信息
*/
export default function (api: typeof babel, options: Options): PluginObj {
const { types: t, template } = api
const { fieldName, items } = options
let pluginsArrayExpression: NodePath<ArrayExpression> | null
if (!fieldName || !items || !items.length)
return {
name: 'add-exports-array',
visitor: {},
}
return {
name: 'add-exports-array',
pre() {
pluginsArrayExpression = null
},
visitor: {
AssignmentExpression(p) {
// 寻找 module.exports = { plugins: [] }
if (
!m
.assignmentExpression(
'=',
m.memberExpression(m.identifier('module'), m.identifier('exports')),
m.objectExpression(),
)
.match(p.node)
)
return
const objectExpression = p.get('right') as NodePath<ObjectExpression>
const properties = objectExpression.get('properties')
properties.forEach(property => {
if (
!m
.objectProperty(m.or(m.stringLiteral(fieldName), m.identifier(fieldName)), m.arrayExpression())
.match(property.node)
)
return
pluginsArrayExpression = property.get('value') as NodePath<ArrayExpression>
})
},
Program: {
exit(p) {
if (!pluginsArrayExpression) {
// 如果找不到 module.exports = { plugins: [] }
// 则在末尾加一句 exports.plugins = (exports.plugins || []).concat([])
const statement = template.statement(`
exports.FIELD_NAME = (exports.FIELD_NAME || []).concat([]);
`)({
FIELD_NAME: t.identifier(fieldName),
})
const [statementPath] = p.pushContainer('body', statement)
pluginsArrayExpression = statementPath.get('expression.right.arguments.0') as NodePath<ArrayExpression>
}
const targetArray = pluginsArrayExpression
// 添加 item
items.forEach(item => {
const [pluginName, option] = Array.isArray(item) ? item : [item]
if (!option) {
targetArray.pushContainer('elements', t.stringLiteral(pluginName))
} else {
targetArray.pushContainer(
'elements',
t.arrayExpression([t.stringLiteral(pluginName), template.expression(JSON.stringify(option))()]),
)
}
})
},
},
},
}
}