eslint-codemod-utils
Advanced tools
Comparing version 0.1.2 to 0.1.3
# eslint-codemod-utils | ||
## 0.1.3 | ||
### Patch Changes | ||
- dd41354: Updates literal and identifiers to support primitive types being passed directly as arguments to AST utility functions. | ||
## 0.1.2 | ||
@@ -4,0 +10,0 @@ |
@@ -52,1 +52,25 @@ "use strict"; | ||
}); | ||
describe('insertImportSpecifier', () => { | ||
test('basic', () => { | ||
const { body } = espree.parse(`import x from 'place'`, ESPREE_OPTIONS); | ||
expect((0, utils_1.insertImportSpecifier)(body[0], 'name').toString()).eq(`import x, { name } from 'place'`); | ||
}); | ||
test('no default', () => { | ||
const { body } = espree.parse(`import { nothing } from 'place'`, ESPREE_OPTIONS); | ||
expect((0, utils_1.insertImportSpecifier)(body[0], 'name').toString()).eq(`import { nothing, name } from 'place'`); | ||
}); | ||
test('with alias', () => { | ||
const { body } = espree.parse(`import x from 'place'`, ESPREE_OPTIONS); | ||
expect((0, utils_1.insertImportSpecifier)(body[0], 'name', 'alias').toString()).eq(`import x, { name as alias } from 'place'`); | ||
}); | ||
}); | ||
describe('removeImportSpecifier', () => { | ||
test('no default', () => { | ||
const { body } = espree.parse(`import { nothing, name } from 'place'`, ESPREE_OPTIONS); | ||
expect((0, utils_1.removeImportSpecifier)(body[0], 'name').toString()).eq(`import { nothing } from 'place'`); | ||
}); | ||
test('with alias', () => { | ||
const { body } = espree.parse(`import x, { name as alias } from 'place'`, ESPREE_OPTIONS); | ||
expect((0, utils_1.removeImportSpecifier)(body[0], 'name').toString()).eq(`import x from 'place'`); | ||
}); | ||
}); |
@@ -1,21 +0,26 @@ | ||
import { Comment, JSXAttribute, JSXClosingElement, JSXClosingFragment, JSXElement, JSXEmptyExpression, JSXExpressionContainer, JSXFragment, JSXIdentifier, JSXMemberExpression, JSXOpeningElement, JSXOpeningFragment, JSXSpreadAttribute, JSXSpreadChild, JSXText, SourceLocation } from 'estree-jsx'; | ||
import type { StringableASTNodeFn } from './types'; | ||
export declare const whiteSpace: (loc?: SourceLocation | undefined) => string; | ||
export declare const comments: (comments?: Comment[]) => { | ||
comments: Comment[]; | ||
import type * as estree from 'estree-jsx'; | ||
import type { StringableASTNode, StringableASTNodeFn, WithoutType } from './types'; | ||
export declare const whiteSpace: (loc?: estree.SourceLocation | undefined) => string; | ||
export declare const comments: (comments?: estree.Comment[]) => { | ||
comments: estree.Comment[]; | ||
toString: () => string; | ||
}; | ||
export declare const comment: ({ value, type, loc }: Comment) => { | ||
export declare const comment: ({ value, type, loc }: estree.Comment) => { | ||
value: string; | ||
type: "Line" | "Block"; | ||
__pragma: string; | ||
toString: () => string; | ||
}; | ||
export declare const jsxIdentifier: StringableASTNodeFn<JSXIdentifier>; | ||
export declare const jsxOpeningFragment: StringableASTNodeFn<JSXOpeningFragment>; | ||
export declare const jsxClosingFragment: StringableASTNodeFn<JSXClosingFragment>; | ||
export declare const jsxFragment: StringableASTNodeFn<JSXFragment>; | ||
export declare const jsxSpreadChild: StringableASTNodeFn<JSXSpreadChild>; | ||
export declare const jsxMemberExpression: StringableASTNodeFn<JSXMemberExpression>; | ||
/** | ||
* __JSXIdentifier__ | ||
* | ||
* @param param Takes a string or the shape of a {estree.JSXIdentifier} node | ||
* @returns {estree.JSXIdentifier} node | ||
*/ | ||
export declare const jsxIdentifier: (param: WithoutType<estree.JSXIdentifier> | string) => StringableASTNode<estree.JSXIdentifier>; | ||
export declare const jsxOpeningFragment: StringableASTNodeFn<estree.JSXOpeningFragment>; | ||
export declare const jsxClosingFragment: StringableASTNodeFn<estree.JSXClosingFragment>; | ||
export declare const jsxFragment: StringableASTNodeFn<estree.JSXFragment>; | ||
export declare const jsxSpreadChild: StringableASTNodeFn<estree.JSXSpreadChild>; | ||
export declare const jsxMemberExpression: StringableASTNodeFn<estree.JSXMemberExpression>; | ||
/** | ||
* __JSXElement__ | ||
@@ -45,3 +50,3 @@ * | ||
*/ | ||
export declare const jsxElement: StringableASTNodeFn<JSXElement>; | ||
export declare const jsxElement: StringableASTNodeFn<estree.JSXElement>; | ||
/** | ||
@@ -69,4 +74,4 @@ * __JSXSpreadAttribute__ | ||
*/ | ||
export declare const jsxSpreadAttribute: StringableASTNodeFn<JSXSpreadAttribute>; | ||
export declare const jsxOpeningElement: StringableASTNodeFn<JSXOpeningElement>; | ||
export declare const jsxSpreadAttribute: StringableASTNodeFn<estree.JSXSpreadAttribute>; | ||
export declare const jsxOpeningElement: StringableASTNodeFn<estree.JSXOpeningElement>; | ||
/** | ||
@@ -85,3 +90,3 @@ * __JSXClosingElement__ | ||
*/ | ||
export declare const jsxClosingElement: StringableASTNodeFn<JSXClosingElement>; | ||
export declare const jsxClosingElement: StringableASTNodeFn<estree.JSXClosingElement>; | ||
/** | ||
@@ -100,5 +105,5 @@ * __JSXText__ | ||
*/ | ||
export declare const jsxText: StringableASTNodeFn<JSXText>; | ||
export declare const jsxEmptyExpression: StringableASTNodeFn<JSXEmptyExpression>; | ||
export declare const jsxExpressionContainer: StringableASTNodeFn<JSXExpressionContainer>; | ||
export declare const jsxText: StringableASTNodeFn<estree.JSXText>; | ||
export declare const jsxEmptyExpression: StringableASTNodeFn<estree.JSXEmptyExpression>; | ||
export declare const jsxExpressionContainer: StringableASTNodeFn<estree.JSXExpressionContainer>; | ||
/** | ||
@@ -117,2 +122,2 @@ * __JSXAttribute__ | ||
*/ | ||
export declare const jsxAttribute: StringableASTNodeFn<JSXAttribute>; | ||
export declare const jsxAttribute: StringableASTNodeFn<estree.JSXAttribute>; |
@@ -16,12 +16,19 @@ "use strict"; | ||
type, | ||
__pragma: 'ecu', | ||
toString: () => (0, exports.whiteSpace)(loc) + (type === 'Line' ? `// ${value}` : `/* ${value} */`), | ||
}); | ||
exports.comment = comment; | ||
const jsxIdentifier = ({ name, }) => ({ | ||
name, | ||
type: 'JSXIdentifier', | ||
__pragma: 'ecu', | ||
toString: () => name, | ||
}); | ||
/** | ||
* __JSXIdentifier__ | ||
* | ||
* @param param Takes a string or the shape of a {estree.JSXIdentifier} node | ||
* @returns {estree.JSXIdentifier} node | ||
*/ | ||
const jsxIdentifier = (param) => { | ||
const name = typeof param === 'string' ? param : param.name; | ||
return { | ||
name, | ||
type: 'JSXIdentifier', | ||
toString: () => name, | ||
}; | ||
}; | ||
exports.jsxIdentifier = jsxIdentifier; | ||
@@ -31,3 +38,2 @@ const jsxOpeningFragment = ({ ...other }) => { | ||
...other, | ||
__pragma: 'ecu', | ||
type: 'JSXOpeningFragment', | ||
@@ -41,3 +47,2 @@ toString: () => `<>`, | ||
...other, | ||
__pragma: 'ecu', | ||
type: 'JSXClosingFragment', | ||
@@ -54,3 +59,2 @@ toString: () => `</>`, | ||
type: 'JSXFragment', | ||
__pragma: 'ecu', | ||
toString: () => { | ||
@@ -68,3 +72,2 @@ return `${(0, node_1.node)(openingFragment)}${children | ||
expression, | ||
__pragma: 'ecu', | ||
type: 'JSXSpreadChild', | ||
@@ -75,5 +78,4 @@ toString: () => `{...${(0, node_1.node)(expression)}}`, | ||
exports.jsxSpreadChild = jsxSpreadChild; | ||
const jsxMemberExpression = ({ object, property, }) => ({ | ||
const jsxMemberExpression = ({ object, property }) => ({ | ||
type: 'JSXMemberExpression', | ||
__pragma: 'ecu', | ||
object, | ||
@@ -127,3 +129,2 @@ property, | ||
type: 'JSXElement', | ||
__pragma: 'ecu', | ||
toString: () => { | ||
@@ -160,4 +161,3 @@ const indent = (0, exports.whiteSpace)(loc); | ||
*/ | ||
const jsxSpreadAttribute = ({ argument, }) => ({ | ||
__pragma: 'ecu', | ||
const jsxSpreadAttribute = ({ argument }) => ({ | ||
type: 'JSXSpreadAttribute', | ||
@@ -168,3 +168,3 @@ argument, | ||
exports.jsxSpreadAttribute = jsxSpreadAttribute; | ||
const jsxOpeningElement = ({ name, attributes = [], selfClosing = false, leadingComments = [], }) => ({ | ||
const jsxOpeningElement = ({ name, attributes = [], selfClosing = false, leadingComments = [] }) => ({ | ||
type: 'JSXOpeningElement', | ||
@@ -174,3 +174,2 @@ name, | ||
selfClosing, | ||
__pragma: 'ecu', | ||
toString: () => `${(0, exports.comments)(leadingComments)}<${name.type === 'JSXIdentifier' | ||
@@ -210,6 +209,5 @@ ? (0, exports.jsxIdentifier)(name) | ||
*/ | ||
const jsxClosingElement = ({ name, }) => { | ||
const jsxClosingElement = ({ name }) => { | ||
return { | ||
type: 'JSXClosingElement', | ||
__pragma: 'ecu', | ||
name, | ||
@@ -233,7 +231,6 @@ toString: () => `</${(0, node_1.node)(name)}>`, | ||
*/ | ||
const jsxText = ({ value, raw }) => ({ | ||
const jsxText = ({ value, raw, }) => ({ | ||
type: 'JSXText', | ||
value, | ||
raw, | ||
__pragma: 'ecu', | ||
toString: () => value, | ||
@@ -246,3 +243,2 @@ }); | ||
type: 'JSXEmptyExpression', | ||
__pragma: 'ecu', | ||
toString: () => `{}`, | ||
@@ -255,3 +251,2 @@ }; | ||
type: 'JSXExpressionContainer', | ||
__pragma: 'ecu', | ||
toString: () => { | ||
@@ -284,3 +279,2 @@ if (expression.type === 'JSXEmptyExpression') { | ||
type: 'JSXAttribute', | ||
__pragma: 'ecu', | ||
name, | ||
@@ -287,0 +281,0 @@ value, |
@@ -1,3 +0,3 @@ | ||
import * as estree from 'estree'; | ||
import { StringableASTNodeFn } from './types'; | ||
import type * as estree from 'estree-jsx'; | ||
import type { StringableASTNode, StringableASTNodeFn, WithoutType } from './types'; | ||
/** | ||
@@ -246,4 +246,4 @@ * __CallExpression__ | ||
export declare const regExpLiteral: StringableASTNodeFn<estree.RegExpLiteral>; | ||
export declare const literal: StringableASTNodeFn<estree.Literal>; | ||
export declare const identifier: StringableASTNodeFn<estree.Identifier>; | ||
export declare const literal: (n: WithoutType<estree.Literal> | (string | number | boolean | null)) => StringableASTNode<estree.Literal>; | ||
export declare const identifier: (param: WithoutType<estree.Identifier> | string) => StringableASTNode<estree.Identifier>; | ||
export declare const doWhileStatement: StringableASTNodeFn<estree.DoWhileStatement>; | ||
@@ -250,0 +250,0 @@ export declare const whileStatement: StringableASTNodeFn<estree.WhileStatement>; |
@@ -669,3 +669,4 @@ "use strict"; | ||
const leadOrEndSpecifier = otherSpecifiers.length > 4 ? '\n' : ' '; | ||
return `import ${defaultSpecifier ? defaultSpecifier.local.name : ''}${otherSpecifiers.length | ||
// @ts-ignore technically not part of espree but the typescript parser does inject it - will support it for now | ||
return `import ${other['importKind'] === 'type' ? 'type ' : ''}${defaultSpecifier ? defaultSpecifier.local.name : ''}${otherSpecifiers.length | ||
? defaultSpecifier | ||
@@ -705,2 +706,14 @@ ? `, {${leadOrEndSpecifier}${otherSpecifiers | ||
const literal = (n) => { | ||
if (typeof n === 'string' || | ||
typeof n === 'boolean' || | ||
typeof n === 'number' || | ||
typeof n === 'undefined' || | ||
n === null) { | ||
return { | ||
raw: String(n), | ||
value: n, | ||
type: 'Literal', | ||
toString: () => String(n), | ||
}; | ||
} | ||
if ('bigint' in n) { | ||
@@ -716,3 +729,2 @@ return (0, exports.bigIntLiteral)(n); | ||
type: 'Literal', | ||
__pragma: 'ecu', | ||
toString: () => n.raw || String(n.value), | ||
@@ -723,12 +735,13 @@ }; | ||
exports.literal = literal; | ||
const identifier = ({ name, }) => ({ | ||
type: 'Identifier', | ||
__pragma: 'ecu', | ||
name, | ||
toString: () => name, | ||
}); | ||
const identifier = (param) => { | ||
const name = typeof param === 'string' ? param : param.name; | ||
return { | ||
type: 'Identifier', | ||
name, | ||
toString: () => name, | ||
}; | ||
}; | ||
exports.identifier = identifier; | ||
const doWhileStatement = ({ test, body, ...other }) => ({ | ||
...other, | ||
__pragma: 'ecu', | ||
test, | ||
@@ -735,0 +748,0 @@ body, |
import type { Node as BaseNode, JSXSpreadChild } from 'estree-jsx'; | ||
import type { Rule } from 'eslint'; | ||
export declare type EslintCodemodUtilsBaseNode = BaseNode | JSXSpreadChild; | ||
export declare type WithoutType<T extends EslintCodemodUtilsBaseNode> = Omit<T, 'type'>; | ||
export declare type RuleListener<T extends EslintNode = EslintNode> = { | ||
@@ -10,3 +11,3 @@ [E in T as E['type']]?: (eventNodeListener: E) => void; | ||
}; | ||
export declare type StringableASTNodeFn<EstreeNodeType extends EslintCodemodUtilsBaseNode> = (node: Omit<EstreeNodeType, 'type'>) => StringableASTNode<EstreeNodeType>; | ||
export declare type StringableASTNodeFn<EstreeNodeType extends EslintCodemodUtilsBaseNode> = (node: WithoutType<EstreeNodeType>) => StringableASTNode<EstreeNodeType>; | ||
export declare type EslintNode = Rule.NodeParentExtension & EslintCodemodUtilsBaseNode; |
@@ -1,6 +0,24 @@ | ||
import type { JSXElement } from 'estree-jsx'; | ||
import type { EslintCodemodUtilsBaseNode, EslintNode } from '../types'; | ||
export declare function isNode<T extends EslintCodemodUtilsBaseNode, K extends EslintCodemodUtilsBaseNode>(node: T, type: K['type']): boolean; | ||
export declare function closestOfType<T extends EslintNode>(node: T, type: EslintNode['type']): EslintNode | null; | ||
import { ImportDeclaration, JSXElement } from 'estree-jsx'; | ||
import type { EslintCodemodUtilsBaseNode, EslintNode, StringableASTNode } from '../types'; | ||
export declare function isNodeOfType<T extends EslintCodemodUtilsBaseNode>(node: EslintCodemodUtilsBaseNode, type: T['type']): node is T; | ||
export declare function closestOfType<T extends EslintNode>(node: EslintNode, type: T['type']): EslintNode | null; | ||
export declare function hasJSXAttribute(node: JSXElement, attributeName: string): boolean; | ||
export declare function hasJSXChild(node: JSXElement, childIdentifier: string): boolean; | ||
/** | ||
* Appends or adds an import specifier to an existing import declaration. | ||
* | ||
* @param declaration | ||
* @param specifierId | ||
* @param specifierAlias | ||
* @returns {StringableASTNode<ImportDeclaration>} | ||
*/ | ||
export declare function insertImportSpecifier(declaration: ImportDeclaration, specifierId: string, specifierAlias?: string): StringableASTNode<ImportDeclaration>; | ||
/** | ||
* Removes an import specifier to an existing import declaration. | ||
* | ||
* @param declaration | ||
* @param specifierId | ||
* @param specifierAlias | ||
* @returns {StringableASTNode<ImportDeclaration>} | ||
*/ | ||
export declare function removeImportSpecifier(declaration: ImportDeclaration, specifierId: string): StringableASTNode<ImportDeclaration>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.hasJSXChild = exports.hasJSXAttribute = exports.closestOfType = exports.isNode = void 0; | ||
function isNode(node, type) { | ||
exports.removeImportSpecifier = exports.insertImportSpecifier = exports.hasJSXChild = exports.hasJSXAttribute = exports.closestOfType = exports.isNodeOfType = void 0; | ||
const nodes_1 = require("../nodes"); | ||
function isNodeOfType(node, type) { | ||
return node.type === type; | ||
} | ||
exports.isNode = isNode; | ||
exports.isNodeOfType = isNodeOfType; | ||
function closestOfType(node, type) { | ||
if (isNode(node, type)) { | ||
if (isNodeOfType(node, type)) { | ||
return node; | ||
@@ -23,3 +24,4 @@ } | ||
return false; | ||
return node.openingElement.attributes.some((attr) => attr.type === 'JSXAttribute' && attr.name.name === attributeName); | ||
return node.openingElement.attributes.some((attr) => isNodeOfType(attr, 'JSXAttribute') && | ||
attr.name.name === attributeName); | ||
} | ||
@@ -37,5 +39,39 @@ exports.hasJSXAttribute = hasJSXAttribute; | ||
node.children | ||
.filter((child) => isNode(child, 'JSXElement')) | ||
.filter((child) => isNodeOfType(child, 'JSXElement')) | ||
.find((child) => hasJSXChild(child, childIdentifier)))); | ||
} | ||
exports.hasJSXChild = hasJSXChild; | ||
/** | ||
* Appends or adds an import specifier to an existing import declaration. | ||
* | ||
* @param declaration | ||
* @param specifierId | ||
* @param specifierAlias | ||
* @returns {StringableASTNode<ImportDeclaration>} | ||
*/ | ||
function insertImportSpecifier(declaration, specifierId, specifierAlias) { | ||
const id = (0, nodes_1.identifier)(specifierId); | ||
return (0, nodes_1.importDeclaration)({ | ||
...declaration, | ||
specifiers: declaration.specifiers.concat((0, nodes_1.importSpecifier)({ | ||
imported: (0, nodes_1.identifier)(specifierId), | ||
local: specifierAlias ? (0, nodes_1.identifier)(specifierAlias) : id, | ||
})), | ||
}); | ||
} | ||
exports.insertImportSpecifier = insertImportSpecifier; | ||
/** | ||
* Removes an import specifier to an existing import declaration. | ||
* | ||
* @param declaration | ||
* @param specifierId | ||
* @param specifierAlias | ||
* @returns {StringableASTNode<ImportDeclaration>} | ||
*/ | ||
function removeImportSpecifier(declaration, specifierId) { | ||
return (0, nodes_1.importDeclaration)({ | ||
...declaration, | ||
specifiers: declaration.specifiers.filter((spec) => !(spec.type === 'ImportSpecifier' && spec.imported.name === specifierId)), | ||
}); | ||
} | ||
exports.removeImportSpecifier = removeImportSpecifier; |
import * as espree from 'espree' | ||
import { closestOfType, hasJSXAttribute } from '../utils/utils' | ||
import { | ||
closestOfType, | ||
hasJSXAttribute, | ||
insertImportSpecifier, | ||
removeImportSpecifier, | ||
} from '../utils/utils' | ||
@@ -41,1 +46,49 @@ const ESPREE_OPTIONS = { | ||
}) | ||
describe('insertImportSpecifier', () => { | ||
test('basic', () => { | ||
const { body } = espree.parse(`import x from 'place'`, ESPREE_OPTIONS) | ||
expect(insertImportSpecifier(body[0], 'name').toString()).eq( | ||
`import x, { name } from 'place'` | ||
) | ||
}) | ||
test('no default', () => { | ||
const { body } = espree.parse( | ||
`import { nothing } from 'place'`, | ||
ESPREE_OPTIONS | ||
) | ||
expect(insertImportSpecifier(body[0], 'name').toString()).eq( | ||
`import { nothing, name } from 'place'` | ||
) | ||
}) | ||
test('with alias', () => { | ||
const { body } = espree.parse(`import x from 'place'`, ESPREE_OPTIONS) | ||
expect(insertImportSpecifier(body[0], 'name', 'alias').toString()).eq( | ||
`import x, { name as alias } from 'place'` | ||
) | ||
}) | ||
}) | ||
describe('removeImportSpecifier', () => { | ||
test('no default', () => { | ||
const { body } = espree.parse( | ||
`import { nothing, name } from 'place'`, | ||
ESPREE_OPTIONS | ||
) | ||
expect(removeImportSpecifier(body[0], 'name').toString()).eq( | ||
`import { nothing } from 'place'` | ||
) | ||
}) | ||
test('with alias', () => { | ||
const { body } = espree.parse( | ||
`import x, { name as alias } from 'place'`, | ||
ESPREE_OPTIONS | ||
) | ||
expect(removeImportSpecifier(body[0], 'name').toString()).eq( | ||
`import x from 'place'` | ||
) | ||
}) | ||
}) |
@@ -1,28 +0,15 @@ | ||
import { | ||
Comment, | ||
JSXAttribute, | ||
JSXClosingElement, | ||
JSXClosingFragment, | ||
JSXElement, | ||
JSXEmptyExpression, | ||
JSXExpressionContainer, | ||
JSXFragment, | ||
JSXIdentifier, | ||
JSXMemberExpression, | ||
JSXOpeningElement, | ||
JSXOpeningFragment, | ||
JSXSpreadAttribute, | ||
JSXSpreadChild, | ||
JSXText, | ||
SourceLocation, | ||
} from 'estree-jsx' | ||
import type * as estree from 'estree-jsx' | ||
import { DEFAULT_WHITESPACE } from './constants' | ||
import type { StringableASTNodeFn } from './types' | ||
import type { | ||
StringableASTNode, | ||
StringableASTNodeFn, | ||
WithoutType, | ||
} from './types' | ||
import { node } from './utils/node' | ||
export const whiteSpace = (loc?: SourceLocation) => | ||
export const whiteSpace = (loc?: estree.SourceLocation) => | ||
''.padStart(loc?.start?.column || 0, ' ') | ||
export const comments = (comments: Comment[] = []) => ({ | ||
export const comments = (comments: estree.Comment[] = []) => ({ | ||
comments, | ||
@@ -33,6 +20,5 @@ toString: () => | ||
export const comment = ({ value, type, loc }: Comment) => ({ | ||
export const comment = ({ value, type, loc }: estree.Comment) => ({ | ||
value, | ||
type, | ||
__pragma: 'ecu', | ||
toString: () => | ||
@@ -42,17 +28,24 @@ whiteSpace(loc!) + (type === 'Line' ? `// ${value}` : `/* ${value} */`), | ||
export const jsxIdentifier: StringableASTNodeFn<JSXIdentifier> = ({ | ||
name, | ||
}) => ({ | ||
name, | ||
type: 'JSXIdentifier', | ||
__pragma: 'ecu', | ||
toString: () => name, | ||
}) | ||
/** | ||
* __JSXIdentifier__ | ||
* | ||
* @param param Takes a string or the shape of a {estree.JSXIdentifier} node | ||
* @returns {estree.JSXIdentifier} node | ||
*/ | ||
export const jsxIdentifier = ( | ||
param: WithoutType<estree.JSXIdentifier> | string | ||
): StringableASTNode<estree.JSXIdentifier> => { | ||
const name = typeof param === 'string' ? param : param.name | ||
return { | ||
name, | ||
type: 'JSXIdentifier', | ||
toString: () => name, | ||
} | ||
} | ||
export const jsxOpeningFragment: StringableASTNodeFn<JSXOpeningFragment> = ({ | ||
...other | ||
}) => { | ||
export const jsxOpeningFragment: StringableASTNodeFn< | ||
estree.JSXOpeningFragment | ||
> = ({ ...other }) => { | ||
return { | ||
...other, | ||
__pragma: 'ecu', | ||
type: 'JSXOpeningFragment', | ||
@@ -63,8 +56,7 @@ toString: () => `<>`, | ||
export const jsxClosingFragment: StringableASTNodeFn<JSXClosingFragment> = ({ | ||
...other | ||
}) => { | ||
export const jsxClosingFragment: StringableASTNodeFn< | ||
estree.JSXClosingFragment | ||
> = ({ ...other }) => { | ||
return { | ||
...other, | ||
__pragma: 'ecu', | ||
type: 'JSXClosingFragment', | ||
@@ -75,3 +67,3 @@ toString: () => `</>`, | ||
export const jsxFragment: StringableASTNodeFn<JSXFragment> = ({ | ||
export const jsxFragment: StringableASTNodeFn<estree.JSXFragment> = ({ | ||
openingFragment, | ||
@@ -87,3 +79,2 @@ closingFragment, | ||
type: 'JSXFragment', | ||
__pragma: 'ecu', | ||
toString: () => { | ||
@@ -97,3 +88,3 @@ return `${node(openingFragment)}${children | ||
export const jsxSpreadChild: StringableASTNodeFn<JSXSpreadChild> = ({ | ||
export const jsxSpreadChild: StringableASTNodeFn<estree.JSXSpreadChild> = ({ | ||
expression, | ||
@@ -105,3 +96,2 @@ ...other | ||
expression, | ||
__pragma: 'ecu', | ||
type: 'JSXSpreadChild', | ||
@@ -112,8 +102,6 @@ toString: () => `{...${node(expression)}}`, | ||
export const jsxMemberExpression: StringableASTNodeFn<JSXMemberExpression> = ({ | ||
object, | ||
property, | ||
}) => ({ | ||
export const jsxMemberExpression: StringableASTNodeFn< | ||
estree.JSXMemberExpression | ||
> = ({ object, property }) => ({ | ||
type: 'JSXMemberExpression', | ||
__pragma: 'ecu', | ||
object, | ||
@@ -129,3 +117,3 @@ property, | ||
const DEFAULT_LOC: SourceLocation = { | ||
const DEFAULT_LOC: estree.SourceLocation = { | ||
start: { | ||
@@ -166,3 +154,3 @@ column: 0, | ||
*/ | ||
export const jsxElement: StringableASTNodeFn<JSXElement> = ({ | ||
export const jsxElement: StringableASTNodeFn<estree.JSXElement> = ({ | ||
openingElement, | ||
@@ -178,3 +166,2 @@ closingElement, | ||
type: 'JSXElement', | ||
__pragma: 'ecu', | ||
toString: (): string => { | ||
@@ -213,6 +200,5 @@ const indent = whiteSpace(loc!) | ||
*/ | ||
export const jsxSpreadAttribute: StringableASTNodeFn<JSXSpreadAttribute> = ({ | ||
argument, | ||
}) => ({ | ||
__pragma: 'ecu', | ||
export const jsxSpreadAttribute: StringableASTNodeFn< | ||
estree.JSXSpreadAttribute | ||
> = ({ argument }) => ({ | ||
type: 'JSXSpreadAttribute', | ||
@@ -223,8 +209,5 @@ argument, | ||
export const jsxOpeningElement: StringableASTNodeFn<JSXOpeningElement> = ({ | ||
name, | ||
attributes = [], | ||
selfClosing = false, | ||
leadingComments = [], | ||
}) => ({ | ||
export const jsxOpeningElement: StringableASTNodeFn< | ||
estree.JSXOpeningElement | ||
> = ({ name, attributes = [], selfClosing = false, leadingComments = [] }) => ({ | ||
type: 'JSXOpeningElement', | ||
@@ -234,3 +217,2 @@ name, | ||
selfClosing, | ||
__pragma: 'ecu', | ||
toString: () => | ||
@@ -274,8 +256,8 @@ `${comments(leadingComments)}<${ | ||
*/ | ||
export const jsxClosingElement: StringableASTNodeFn<JSXClosingElement> = ({ | ||
name, | ||
}) => { | ||
export const jsxClosingElement: StringableASTNodeFn< | ||
estree.JSXClosingElement | ||
> = ({ name }) => { | ||
return { | ||
type: 'JSXClosingElement', | ||
__pragma: 'ecu', | ||
name, | ||
@@ -299,17 +281,18 @@ toString: () => `</${node(name)}>`, | ||
*/ | ||
export const jsxText: StringableASTNodeFn<JSXText> = ({ value, raw }) => ({ | ||
export const jsxText: StringableASTNodeFn<estree.JSXText> = ({ | ||
value, | ||
raw, | ||
}) => ({ | ||
type: 'JSXText', | ||
value, | ||
raw, | ||
__pragma: 'ecu', | ||
toString: () => value, | ||
}) | ||
export const jsxEmptyExpression: StringableASTNodeFn<JSXEmptyExpression> = ( | ||
node | ||
) => { | ||
export const jsxEmptyExpression: StringableASTNodeFn< | ||
estree.JSXEmptyExpression | ||
> = (node) => { | ||
return { | ||
...node, | ||
type: 'JSXEmptyExpression', | ||
__pragma: 'ecu', | ||
toString: () => `{}`, | ||
@@ -320,7 +303,6 @@ } | ||
export const jsxExpressionContainer: StringableASTNodeFn< | ||
JSXExpressionContainer | ||
estree.JSXExpressionContainer | ||
> = ({ expression }) => ({ | ||
expression, | ||
type: 'JSXExpressionContainer', | ||
__pragma: 'ecu', | ||
toString: () => { | ||
@@ -353,3 +335,3 @@ if (expression.type === 'JSXEmptyExpression') { | ||
*/ | ||
export const jsxAttribute: StringableASTNodeFn<JSXAttribute> = ({ | ||
export const jsxAttribute: StringableASTNodeFn<estree.JSXAttribute> = ({ | ||
name, | ||
@@ -359,3 +341,2 @@ value, | ||
type: 'JSXAttribute', | ||
__pragma: 'ecu', | ||
name, | ||
@@ -371,3 +352,3 @@ value, | ||
? jsxElement(value) | ||
: jsxExpressionContainer(value as JSXExpressionContainer) | ||
: jsxExpressionContainer(value as estree.JSXExpressionContainer) | ||
}` | ||
@@ -374,0 +355,0 @@ : '' |
@@ -1,4 +0,8 @@ | ||
import * as estree from 'estree' | ||
import type * as estree from 'estree-jsx' | ||
import { StringableASTNodeFn } from './types' | ||
import type { | ||
StringableASTNode, | ||
StringableASTNodeFn, | ||
WithoutType, | ||
} from './types' | ||
import { node } from './utils/node' | ||
@@ -849,3 +853,6 @@ import { DEFAULT_WHITESPACE } from './constants' | ||
return `import ${defaultSpecifier ? defaultSpecifier.local.name : ''}${ | ||
// @ts-ignore technically not part of espree but the typescript parser does inject it - will support it for now | ||
return `import ${other['importKind'] === 'type' ? 'type ' : ''}${ | ||
defaultSpecifier ? defaultSpecifier.local.name : '' | ||
}${ | ||
otherSpecifiers.length | ||
@@ -900,3 +907,20 @@ ? defaultSpecifier | ||
export const literal: StringableASTNodeFn<estree.Literal> = (n) => { | ||
export const literal = ( | ||
n: WithoutType<estree.Literal> | (string | number | boolean | null) | ||
): StringableASTNode<estree.Literal> => { | ||
if ( | ||
typeof n === 'string' || | ||
typeof n === 'boolean' || | ||
typeof n === 'number' || | ||
typeof n === 'undefined' || | ||
n === null | ||
) { | ||
return { | ||
raw: String(n), | ||
value: n, | ||
type: 'Literal', | ||
toString: () => String(n), | ||
} | ||
} | ||
if ('bigint' in n) { | ||
@@ -910,3 +934,2 @@ return bigIntLiteral(n as estree.BigIntLiteral) | ||
type: 'Literal', | ||
__pragma: 'ecu', | ||
toString: () => n.raw || String(n.value), | ||
@@ -917,10 +940,12 @@ } | ||
export const identifier: StringableASTNodeFn<estree.Identifier> = ({ | ||
name, | ||
}) => ({ | ||
type: 'Identifier', | ||
__pragma: 'ecu', | ||
name, | ||
toString: () => name, | ||
}) | ||
export const identifier = ( | ||
param: WithoutType<estree.Identifier> | string | ||
): StringableASTNode<estree.Identifier> => { | ||
const name = typeof param === 'string' ? param : param.name | ||
return { | ||
type: 'Identifier', | ||
name, | ||
toString: () => name, | ||
} | ||
} | ||
@@ -933,3 +958,2 @@ export const doWhileStatement: StringableASTNodeFn<estree.DoWhileStatement> = ({ | ||
...other, | ||
__pragma: 'ecu', | ||
test, | ||
@@ -936,0 +960,0 @@ body, |
@@ -5,2 +5,3 @@ import type { Node as BaseNode, JSXSpreadChild } from 'estree-jsx' | ||
export type EslintCodemodUtilsBaseNode = BaseNode | JSXSpreadChild | ||
export type WithoutType<T extends EslintCodemodUtilsBaseNode> = Omit<T, 'type'> | ||
@@ -18,4 +19,4 @@ export type RuleListener<T extends EslintNode = EslintNode> = { | ||
EstreeNodeType extends EslintCodemodUtilsBaseNode | ||
> = (node: Omit<EstreeNodeType, 'type'>) => StringableASTNode<EstreeNodeType> | ||
> = (node: WithoutType<EstreeNodeType>) => StringableASTNode<EstreeNodeType> | ||
export type EslintNode = Rule.NodeParentExtension & EslintCodemodUtilsBaseNode |
@@ -1,8 +0,18 @@ | ||
import type { JSXElement, JSXIdentifier } from 'estree-jsx' | ||
import type { EslintCodemodUtilsBaseNode, EslintNode } from '../types' | ||
import { | ||
ImportDeclaration, | ||
JSXAttribute, | ||
JSXElement, | ||
JSXIdentifier, | ||
} from 'estree-jsx' | ||
import { identifier, importDeclaration, importSpecifier } from '../nodes' | ||
import type { | ||
EslintCodemodUtilsBaseNode, | ||
EslintNode, | ||
StringableASTNode, | ||
} from '../types' | ||
export function isNode< | ||
T extends EslintCodemodUtilsBaseNode, | ||
K extends EslintCodemodUtilsBaseNode | ||
>(node: T, type: K['type']) { | ||
export function isNodeOfType<T extends EslintCodemodUtilsBaseNode>( | ||
node: EslintCodemodUtilsBaseNode, | ||
type: T['type'] | ||
): node is T { | ||
return node.type === type | ||
@@ -12,6 +22,6 @@ } | ||
export function closestOfType<T extends EslintNode>( | ||
node: T, | ||
type: EslintNode['type'] | ||
node: EslintNode, | ||
type: T['type'] | ||
): EslintNode | null { | ||
if (isNode(node, type)) { | ||
if (isNodeOfType(node, type)) { | ||
return node | ||
@@ -33,3 +43,5 @@ } | ||
return node.openingElement.attributes.some( | ||
(attr) => attr.type === 'JSXAttribute' && attr.name.name === attributeName | ||
(attr) => | ||
isNodeOfType<JSXAttribute>(attr, 'JSXAttribute') && | ||
attr.name.name === attributeName | ||
) | ||
@@ -56,3 +68,5 @@ } | ||
node.children | ||
.filter((child): child is JSXElement => isNode(child, 'JSXElement')) | ||
.filter((child): child is JSXElement => | ||
isNodeOfType(child, 'JSXElement') | ||
) | ||
.find((child) => hasJSXChild(child, childIdentifier)) | ||
@@ -62,1 +76,47 @@ ) | ||
} | ||
/** | ||
* Appends or adds an import specifier to an existing import declaration. | ||
* | ||
* @param declaration | ||
* @param specifierId | ||
* @param specifierAlias | ||
* @returns {StringableASTNode<ImportDeclaration>} | ||
*/ | ||
export function insertImportSpecifier( | ||
declaration: ImportDeclaration, | ||
specifierId: string, | ||
specifierAlias?: string | ||
): StringableASTNode<ImportDeclaration> { | ||
const id = identifier(specifierId) | ||
return importDeclaration({ | ||
...declaration, | ||
specifiers: declaration.specifiers.concat( | ||
importSpecifier({ | ||
imported: identifier(specifierId), | ||
local: specifierAlias ? identifier(specifierAlias) : id, | ||
}) | ||
), | ||
}) | ||
} | ||
/** | ||
* Removes an import specifier to an existing import declaration. | ||
* | ||
* @param declaration | ||
* @param specifierId | ||
* @param specifierAlias | ||
* @returns {StringableASTNode<ImportDeclaration>} | ||
*/ | ||
export function removeImportSpecifier( | ||
declaration: ImportDeclaration, | ||
specifierId: string | ||
): StringableASTNode<ImportDeclaration> { | ||
return importDeclaration({ | ||
...declaration, | ||
specifiers: declaration.specifiers.filter( | ||
(spec) => | ||
!(spec.type === 'ImportSpecifier' && spec.imported.name === specifierId) | ||
), | ||
}) | ||
} |
{ | ||
"name": "eslint-codemod-utils", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "A collection of AST helper functions for more complex ESLint rule fixes.", | ||
@@ -5,0 +5,0 @@ "source": "lib/index.ts", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
682619
20863