Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ class ClassName {
}
```

Platform-specific suffixes (e.g. `.android.ts`, `.ios.ts`) are stripped from the filename, so `SomeClass.android.ts` expects `SomeClass` in the logging, not `SomeClass.android`:
```typescript
// SomeClass.android.ts
function functionName(){
Log.trace('SomeClass:functionName');
}
```

## Configuration

By default the rule applies to all functions. You can optionally provide an `ignoreList` list of regex patterns — any function whose name matches a pattern is exempt from the rule.
Expand Down
44 changes: 44 additions & 0 deletions dist/rules/__tests__/no-function-without-logging.test.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 11 additions & 6 deletions dist/rules/no-function-without-logging.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions src/rules/__tests__/no-function-without-logging.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ ruleTester.run("no-function-without-logging", rule, {
filename: "Component",
code: "const Component = () => { Log.debug('Component') }",
},
{
name: "Platform-specific suffix is stripped from filename in logging",
filename: "SomeClass.android.ts",
code: "function functionName(){ Log.debug('SomeClass:functionName') }",
},
{
name: "Ignored function declaration is skipped",
options: [{ ignoreList: ["ignoredFunction"] }],
Expand Down Expand Up @@ -215,6 +220,48 @@ ruleTester.run("no-function-without-logging", rule, {
},
],
},
{
name: "Missing logging in function declaration in platform-specific file",
filename: "SomeClass.android.ts",
code: "function functionName(){}",
errors: [
{
messageId: "missingLogging",
data: { expectedLogging: "SomeClass:functionName" },
suggestions: [
{
messageId: "addLoggingSuggestion",
data: { suggestedCode: "Log.trace('SomeClass:functionName');" },
output:
"function functionName(){Log.trace('SomeClass:functionName');}",
},
{
messageId: "addLoggingSuggestion",
data: { suggestedCode: "Log.debug('SomeClass:functionName');" },
output:
"function functionName(){Log.debug('SomeClass:functionName');}",
},
],
},
],
},
{
name: "Incorrect logging using full filename with platform suffix",
filename: "SomeClass.android.ts",
code: "function functionName(){ Log.debug('SomeClass.android:functionName') }",
errors: [
{
messageId: "incorrectLogging",
suggestions: [
{
messageId: "incorrectLogging",
output:
"function functionName(){ Log.debug('SomeClass:functionName') }",
},
],
},
],
},
{
name: "Missing function name in logging",
code: "function functionName(){ Log.debug('file') }",
Expand Down
18 changes: 12 additions & 6 deletions src/rules/no-function-without-logging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ type messageIds = "incorrectLogging" | "missingLogging" | "addLoggingSuggestion"

type Options = [{ ignoreList?: string[] }]

const getClassName = (filename: string): string => {
const base = path.basename(filename)
const firstDotIndex = base.indexOf(".")
return firstDotIndex === -1 ? base : base.slice(0, firstDotIndex)
}

const isIgnored = (functionName: string | null, patterns: string[]): boolean => {
if (!functionName || patterns.length === 0) return false
return patterns.some((pattern) => new RegExp(pattern).test(functionName))
Expand Down Expand Up @@ -137,9 +143,9 @@ const checkFunctionDeclaration = (
const functionName = node.id ? node.id.name : ""
if (isIgnored(functionName, ignoreList)) return

const file = path.parse(context.getFilename())
const className = getClassName(context.getFilename())

const correctLogging = `${file.name}:${functionName}`
const correctLogging = `${className}:${functionName}`
if (!containsLoggingStatement(node.body)) {
addMissingLogStatementSuggestions(context, node, node.body, correctLogging)
}
Expand All @@ -151,7 +157,7 @@ const checkCallExpression = (
ignoreList: string[]
) => {
if (isLogStatement(node)) {
const filename = path.parse(context.getFilename()).name
const filename = getClassName(context.getFilename())
const functionName = getFunctionName(node)
if (isIgnored(functionName, ignoreList)) return
const expectedLogging = filename === functionName ? filename : `${filename}:${functionName}`
Expand Down Expand Up @@ -219,7 +225,7 @@ const checkVariableDeclaration = (
) {
const { body } = declaration.init

const filename = path.parse(context.getFilename()).name
const filename = getClassName(context.getFilename())
const functionName = declaration.id.name

const isComponentDeclaration = filename === functionName
Expand All @@ -245,7 +251,7 @@ const checkPropertyDefinition = (
isBlockStatement(node.value.body)
) {
const { body } = node.value
const filename = path.parse(context.getFilename()).name
const filename = getClassName(context.getFilename())
const functionName = node.key.name

if (isIgnored(functionName, ignoreList)) return
Expand Down Expand Up @@ -284,7 +290,7 @@ const checkMethodDefinition = (

if (isFunctionExpression(node.value) && isIdentifier(node.key)) {
const { body } = node.value
const filename = path.parse(context.getFilename()).name
const filename = getClassName(context.getFilename())
const functionName = node.key.name

if (isSetterLikeMethodDefinition(node, functionName)) return
Expand Down