Comprehensive utility functions for AST analysis and Ember-specific pattern detection. These utilities are primarily used for developing custom ESLint rules and analyzing Ember.js code patterns.
Functions for detecting Ember core modules and framework components.
/**
* Check if a node represents an Ember Data model
* @param node - AST node to check
* @param filePath - Optional file path for additional context
* @returns {boolean} True if node is a DS.Model
*/
function isDSModel(node: ASTNode, filePath?: string): boolean;
/**
* Check if a node represents a specific Ember module
* @param node - AST node to check
* @param element - Module element name (e.g., 'Component', 'Service')
* @param moduleName - Module namespace (default: 'Ember')
* @returns {boolean} True if node matches the module pattern
*/
function isModule(node: ASTNode, element: string, moduleName?: string): boolean;
/**
* Check if a file path indicates a specific module type
* @param filePath - File path to analyze
* @param module - Module type to check for
* @returns {boolean} True if file path matches module pattern
*/
function isModuleByFilePath(filePath: string, module: string): boolean;
/**
* Check if a node is any Ember core module
* @param context - ESLint context
* @param node - AST node to check
* @returns {boolean} True if node is any Ember core module
*/
function isAnyEmberCoreModule(context: ESLintContext, node: ASTNode): boolean;Usage Examples:
const emberUtils = require('eslint-plugin-ember').utils.ember;
// Check if node is a DS.Model
if (emberUtils.isDSModel(node, context.getFilename())) {
// Handle Ember Data model
}
// Check if node is an Ember Component
if (emberUtils.isModule(node, 'Component')) {
// Handle component definition
}
// Check if file is a controller by path
if (emberUtils.isModuleByFilePath('/app/controllers/user.js', 'controller')) {
// Handle controller file
}Specific functions for detecting different types of Ember core modules.
/**
* Check if node is an Ember Component
*/
function isEmberComponent(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is a Glimmer Component
*/
function isGlimmerComponent(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is an Ember Controller
*/
function isEmberController(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is an Ember Mixin
*/
function isEmberMixin(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is an Ember Route
*/
function isEmberRoute(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is an Ember Service
*/
function isEmberService(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is an ArrayProxy
*/
function isEmberArrayProxy(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is an ObjectProxy
*/
function isEmberObjectProxy(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is an EmberObject
*/
function isEmberObject(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is an Ember Helper
*/
function isEmberHelper(context: ESLintContext, node: ASTNode): boolean;
/**
* Check if node is any Ember proxy type
*/
function isEmberProxy(context: ESLintContext, node: ASTNode): boolean;Usage Examples:
// In a custom ESLint rule
create(context) {
return {
ClassDeclaration(node) {
if (emberUtils.isEmberComponent(context, node)) {
// Handle Ember component class
}
if (emberUtils.isGlimmerComponent(context, node)) {
// Handle Glimmer component class
}
},
CallExpression(node) {
if (emberUtils.isEmberService(context, node)) {
// Handle service definition
}
}
};
}Functions for detecting different types of properties in Ember objects.
/**
* Check if property is a service injection
* @param node - Property node to check
* @param importedEmberName - Name Ember is imported as
* @param importedInjectName - Name inject is imported as
*/
function isInjectedServiceProp(node: ASTNode, importedEmberName: string, importedInjectName: string): boolean;
/**
* Check if property is a controller injection
*/
function isInjectedControllerProp(node: ASTNode, importedEmberName: string, importedControllerName: string): boolean;
/**
* Check if property is an observer
*/
function isObserverProp(node: ASTNode, importedEmberName: string, importedObserverName: string): boolean;
/**
* Check if property is a computed property
* @param options - Configuration options for computed property detection
*/
function isComputedProp(
node: ASTNode,
importedEmberName: string,
importedComputedName: string,
options?: ComputedPropOptions
): boolean;
interface ComputedPropOptions {
/** Include properties with suffixes like .volatile() */
includeSuffix?: boolean;
/** Include computed property macros like computed.and() */
includeMacro?: boolean;
}
/**
* Check if property is an object property
*/
function isObjectProp(node: ASTNode): boolean;
/**
* Check if property is an array property
*/
function isArrayProp(node: ASTNode): boolean;
/**
* Check if property is a custom property
*/
function isCustomProp(property: ASTNode): boolean;
/**
* Check if property is an actions hash
*/
function isActionsProp(property: ASTNode): boolean;
/**
* Check if property is an Ember Data relationship
*/
function isRelation(property: ASTNode): boolean;Usage Examples:
// Detect service injections
if (emberUtils.isInjectedServiceProp(property, 'Ember', 'service')) {
// Handle service injection
}
// Detect computed properties with options
if (emberUtils.isComputedProp(property, 'Ember', 'computed', {
includeSuffix: true,
includeMacro: true
})) {
// Handle computed property
}
// Detect actions hash
if (emberUtils.isActionsProp(property)) {
// Report actions hash usage
}Functions for detecting various lifecycle hooks in Ember objects.
/**
* Check if property is a route lifecycle hook
*/
function isRouteLifecycleHook(property: ASTNode): boolean;
/**
* Check if property is a component lifecycle hook
*/
function isComponentLifecycleHook(property: ASTNode): boolean;
/**
* Check if property is a Glimmer component lifecycle hook
*/
function isGlimmerComponentLifecycleHook(property: ASTNode): boolean;Usage Examples:
// Check for lifecycle hooks in components
if (emberUtils.isComponentLifecycleHook(property)) {
context.report({
node: property,
message: 'Component lifecycle hooks are deprecated'
});
}
// Validate route lifecycle hooks
if (emberUtils.isRouteLifecycleHook(property)) {
// Ensure proper super calls
}Functions for analyzing function patterns and expressions.
/**
* Check if property is a single-line function
*/
function isSingleLineFn(property: ASTNode, importedEmberName: string, importedObserverName: string): boolean;
/**
* Check if property is a multi-line function
*/
function isMultiLineFn(property: ASTNode, importedEmberName: string, importedObserverName: string): boolean;
/**
* Check if property is a function expression
*/
function isFunctionExpression(property: ASTNode): boolean;Functions for detecting Ember object patterns and method calls.
/**
* Check if node uses extend() pattern
*/
function isExtendObject(node: ASTNode): boolean;
/**
* Check if node uses reopen() pattern
*/
function isReopenObject(node: ASTNode): boolean;
/**
* Check if node uses reopenClass() pattern
*/
function isReopenClassObject(node: ASTNode): boolean;
/**
* Check if node is a route() call
*/
function isRoute(node: ASTNode): boolean;Functions for analyzing computed properties and their dependencies.
/**
* Parse dependent keys from a computed property call
* @param callExp - Call expression to analyze
* @returns {string[]} Array of dependent key strings
*/
function parseDependentKeys(callExp: ASTNode): string[];
/**
* Unwrap brace expressions in dependent keys
* @param dependentKeys - Array of dependent key strings
* @returns {string[]} Expanded dependent keys
*/
function unwrapBraceExpressions(dependentKeys: string[]): string[];
/**
* Check if computed property has duplicate dependent keys
*/
function hasDuplicateDependentKeys(
callExp: ASTNode,
importedEmberName: string,
importedComputedName: string
): boolean;Usage Examples:
// Analyze computed property dependencies
const dependentKeys = emberUtils.parseDependentKeys(computedCall);
const expandedKeys = emberUtils.unwrapBraceExpressions(dependentKeys);
// Check for duplicates
if (emberUtils.hasDuplicateDependentKeys(computedCall, 'Ember', 'computed')) {
context.report({
node: computedCall,
message: 'Computed property has duplicate dependent keys'
});
}Functions for analyzing file context and detecting test files.
/**
* Check if filename represents a test file
* @param fileName - File name to check
* @returns {boolean} True if file is a test file
*/
function isTestFile(fileName: string): boolean;
/**
* Check if filename is in a Mirage directory
*/
function isMirageDirectory(fileName: string): boolean;
/**
* Check if filename is a Mirage config file
*/
function isMirageConfig(fileName: string): boolean;Functions for analyzing module structure and imports.
/**
* Get properties from an Ember module definition
* @param moduleNode - Module definition node
* @param scopeManager - ESLint scope manager
* @returns {ASTNode[]} Array of property nodes
*/
function getModuleProperties(moduleNode: ASTNode, scopeManager: ScopeManager): ASTNode[];
/**
* Get alias name for default Ember import
* @param importDeclaration - Import declaration node
* @returns {string|null} Import alias name or null
*/
function getEmberImportAliasName(importDeclaration: ASTNode): string | null;Advanced utility functions for complex pattern detection.
/**
* Check if EmberObject implements unknownProperty
*/
function isEmberObjectImplementingUnknownProperty(node: ASTNode, scopeManager: ScopeManager): boolean;
/**
* Check if decorator is an observer decorator
*/
function isObserverDecorator(node: ASTNode, importedObservesName: string): boolean;
/**
* Convert service name to kebab-case
* @param serviceName - Service name to convert
* @returns {string} Kebab-cased service name
*/
function convertServiceNameToKebabCase(serviceName: string): string;Usage Examples:
// Check for unknownProperty implementation
if (emberUtils.isEmberObjectImplementingUnknownProperty(classNode, scopeManager)) {
// Handle unknownProperty usage
}
// Convert service names
const kebabName = emberUtils.convertServiceNameToKebabCase('currentUser');
// Returns: 'current-user'