hypermod/utils
Hypermod provides a set of utilities to help perform common codemod operations.
Installation
@hypermod/utils
is pre-bundled with every codemod that is published to the public registry,
so there's no need to install it manually.
However, it is also available for use outside of this project and compatible with jscodeshift.
npm install --save-dev @hypermod/utils
or yarn add -D @hypermod/utils
Nodes
isNodeOfType
isNodeOfType(node, type)
The isNodeOfType
function uses generics to check if a node of type ASTNode
is of a specified type.
If the check passes, the type of node is narrowed to the expected type, ensuring that the returned type of the function is always correct.
Returns
boolean
Example
const isImportSpecifier = isNodeOfType(node, 'ImportSpecifier');
isDecendantOfType
isDecendantOfType(j, path, type)
The isDecendantOfType
function traverses the AST to determind if the given path is a child of a node of the specified type.
Returns
boolean
Example
const isChildOfImportSpecifier = isDecendantOfType(j, path, j.ImportSpecifier);
Imports
hasImportDeclaration
hasImportDeclaration(j, source, sourcePath)
Finds an import declaration by source name
Returns
boolean
Example
// src/App.js
import React from 'react';
import { hasImportDeclaration } from '@hypermod/utils';
hasImportDeclaration(j, source, 'react'); // True
getImportDeclaration
getImportDeclaration(j, source, sourcePath)
Returns an import declaration by source name
Returns
Collection
: Collection containing 1 or more imports
Example
// src/App.js
import React from 'react';
import { getImportDeclaration } from '@hypermod/utils';
getImportDeclaration(j, source, 'react');
removeImportDeclaration
removeImportDeclaration(j, source, sourcePath)
Removes an import declaration by source name
Returns
void
Example
// src/App.js
import React from 'react';
import { removeImportDeclaration } from '@hypermod/utils';
removeImportDeclaration(j, source, 'react');
// src/App.js
-import React, { useEffect } from 'react';
renameImportDeclaration
renameImportDeclaration(j, source, sourcePath, newSourcePath)
Renames an import declaration by source name
Returns
void
Example
// src/App.js
import React from 'react';
import { renameImportDeclaration } from '@hypermod/utils';
renameImportDeclaration(j, source, 'react', 'preact');
// src/App.js
-import React, { useEffect } from 'react';
+import React, { useEffect } from 'preact';
getDefaultImportSpecifier
getDefaultImportSpecifier(j, source, sourcePath)
Finds a default import specifier
Returns
Collection
: Collection containing all matched default import specifiers
Example
// src/App.js
import React from 'react';
import { getDefaultImportSpecifier } from '@hypermod/utils';
getDefaultImportSpecifier(j, source, 'react'); // Collection containing 'React'
getDefaultImportSpecifierName
getDefaultImportSpecifierName(j, source, sourcePath)
Finds a default import specifier and returns its name
Returns
string | null
: Default import's name
Example
// src/App.js
import React from 'react';
import { getDefaultImportSpecifierName } from '@hypermod/utils';
getDefaultImportSpecifierName(j, source, 'react'); // Collection containing 'React'
hasDefaultImportSpecifier
hasDefaultImportSpecifier(j, source, sourcePath)
Attempts to find a default import specifier and returns a boolean result
Returns
boolean
Example
// src/App.js
import React from 'react';
import { hasDefaultImportSpecifier } from '@hypermod/utils';
hasDefaultImportSpecifier(j, source, 'react'); // True
removeDefaultImportSpecifier
removeDefaultImportSpecifier(j, source, sourcePath)
Attempts to remove a default import specifier
Returns
void
Example
// src/App.js
import React, { useEffect } from 'react';
import { removeDefaultImportSpecifier } from '@hypermod/utils';
removeDefaultImportSpecifier(j, source, 'React');
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
hasImportSpecifier
hasImportSpecifier(j, source, sourcePath)
Checks for an import import specifier
Returns
boolean
Example
// src/App.js
import React, { useEffect } from 'react';
import { hasImportSpecifier } from '@hypermod/utils';
hasImportSpecifier(j, source, 'react', 'useEffect'); // True
getImportSpecifier
getImportSpecifier(j, specifier, source)
Finds an import specifier by name
Returns
Collection
: Collection containing all matched import specifiers
Example
// src/App.js
import React, { useEffect } from 'react';
import { getImportSpecifier } from '@hypermod/utils';
getImportSpecifier(j, source, 'useEffect'); // Collection containing 'useEffect'
getImportSpecifierName
getImportSpecifierName(j, specifier, source)
Returns the local name of an import. This is useful for cases where an import specifier is potentially aliased.
Returns
string
| null: specifier name or null if not found
Example
// src/App.js
import React, { useEffect as foo } from 'react';
import { getImportSpecifierName } from '@hypermod/utils';
getImportSpecifierName(j, source, 'useEffect', 'react'); // 'foo'
insertImportSpecifier
insertImportSpecifier(j, source, specifier)
Inserts an import specifier
Returns
void
Example
// src/App.js
import React, { useEffect } from 'react';
import { insertImportSpecifier } from '@hypermod/utils';
insertImportSpecifier(j, source, 'useMemo', 'react'); // Collection containing 'useEffect'
// src/App.js
-import React, { useEffect } from 'react';
+import React, { useEffect, useMemo } from 'react';
removeImportSpecifier
removeImportSpecifier(j, source, specifier)
Removes an import specifier
Returns
void
Example
// src/App.js
import React, { useEffect } from 'react';
import { removeImportSpecifier } from '@hypermod/utils';
removeImportSpecifier(j, source, 'useMemo', 'react'); // Collection containing 'useEffect'
// src/App.js
-import React, { useEffect } from 'react';
+import React, { useEffect, useMemo } from 'react';
JSX
getJSXAttributes
getJSXAttributes(j, source, attributeName)
Finds a JSX attributeName (aka prop) by name
Returns
Collection
: Collection containing all matched jsx attributes
Example
// src/App.js
import React from 'react';
const App = () => <Button primary>Say hello</Button>;
import { getJSXAttributes } from '@hypermod/utils';
getJSXAttributes(j, source, 'primary'); // Collection containing 'primary'
hasJSXAttributes
hasJSXAttributes(j, source, attributeName)
Finds a JSX attributeName (aka prop) by name and returns true if found
Returns
boolean
Example
// src/App.js
import React from 'react';
const App = () => <Button primary>Say hello</Button>;
import { hasJSXAttributes } from '@hypermod/utils';
hasJSXAttributes(j, source, 'primary'); // Found!
Comments
insertCommentBefore
insertCommentBefore(j, source, message, prefix)
Appends a comment before the provided node
Returns
void
Example
// src/App.js
import React from 'react';
const App = () => <Button primary>Say hello</Button>;
import { insertCommentBefore } from '@hypermod/utils';
insertCommentBefore(
j,
path.find(j.ImportDeclaration),
'This should be removed in favour of mylib',
);
// src/App.js
import React from 'react';
// TODO: (@hypermod) This should be removed in favour of mylib
const App = () => <Button primary>Say hello</Button>;
insertCommentToStartOfFile
insertCommentToStartOfFile(j, source, message)
Appends a comment to the start of a file
Returns
void
Example
// src/App.js
import React from 'react';
const App = () => <Button primary>Say hello</Button>;
import { insertCommentToStartOfFile } from '@hypermod/utils';
insertCommentToStartOfFile(
j,
path.find(j.ImportDeclaration),
'This should be removed in favour of mylib',
);
// src/App.js
// TODO: (Codemod) This should be removed in favour of mylib
import React from 'react';
const App = () => <Button primary>Say hello</Button>;
Motions
applyMotions
applyMotions(j, source, motions)
A helper function to apply an array of motions in sequence.
Returns
void
Example
import { applyMotions } from '@hypermod/utils';
import { sortImports } from './motions';
applyMotions(j, j(fileInfo.source), [sortImports, removeVar]);
Testing
applyTransform
applyTransform(transform, input, options = { parser: 'babel' })
Runs a transform against the provided code and returns the resulting file.
We provide this method as opposed to jscodeshift's test utils to maintain jest's skip/only and snapshot features
Returns
Promise<string>
: Resulting file after transform has been applied
Example
import * as transformer from '../transform';
import { applyTransform } from '@hypermod/utils';
it('should wrap avatar in a tooltip if name is defined', async () => {
const result = await applyTransform(
transformer,
`
import Avatar from 'avatar';
const App = () => {
return <Avatar name="foo" />;
}
`,
{ parser: 'tsx' },
);
expect(result).toMatchInlineSnapshot(`
"import Tooltip from 'tooltip';
import Avatar from 'avatar';
const App = () => {
return <Tooltip content=\\"foo\\"><Avatar name=\\"foo\\" /></Tooltip>;
}"
`);
});