# shared/analyzers/sink.analyzer.ts

> 41 lines of code and 12 definitions.

Tree: Governance tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/governance#file-governance-shared-analyzers-sink-analyzer-ts
Source text: https://banes-lab.com/source/governance/shared/analyzers/sink.analyzer.ts.txt

Listed in [shared/analyzers](https://banes-lab.com/api/source/governance/shared/analyzers.md), after [shared/analyzers/sentence.analyzer.ts](https://banes-lab.com/source/governance/shared/analyzers/sentence.analyzer.ts.md) and before [shared/analyzers/specifier.analyzer.ts](https://banes-lab.com/source/governance/shared/analyzers/specifier.analyzer.ts.md).

## Definitions

- `identName` (lexical_declaration, line 11, exported)
- `calledName` (lexical_declaration, line 15, exported)
- `parentWriteMissingUtf8` (lexical_declaration, line 36, exported)
- `isJsonStringify` (lexical_declaration, line 23, exported)
- `encodingOf` (lexical_declaration, line 7)
- `stringValue` (lexical_declaration, line 32)
- `isFileWriteCall` (lexical_declaration, line 47, exported)
- `WRITE_METHODS` (lexical_declaration, line 3)
- `FILE_WRITE_FNS` (lexical_declaration, line 4)
- `UTF8` (lexical_declaration, line 5)
- `{ callee }` (lexical_declaration, line 24, exported)
- `{ parent }` (lexical_declaration, line 37, exported)

## Used by

- [rules/eslint/no-raw-file-write.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/no-raw-file-write.eslint.rule.ts.md)
- [shared/analyzers/generator.analyzer.ts](https://banes-lab.com/source/governance/shared/analyzers/generator.analyzer.ts.md)

## Source

```typescript
import type { WriteNode } from "../../types/generator.types.ts";

const WRITE_METHODS = new Set(["write", "writeFile", "writeFileSync", "writeSync"]);
const FILE_WRITE_FNS = new Set(["writeFile", "writeFileSync"]);
const UTF8 = "utf8";

const encodingOf = function encodingOf(value: string): string {
    return value.toLowerCase().split("-").join("");
};

export const identName = function identName(node: WriteNode | undefined): string | null {
    return node?.type === "Identifier" && typeof node.name === "string" ? node.name : null;
};

export const calledName = function calledName(node: WriteNode): string | null {
    const { callee } = node;
    if (callee?.type === "Identifier") {
        return identName(callee);
    }
    return callee?.type === "MemberExpression" ? identName(callee.property) : null;
};

export const isJsonStringify = function isJsonStringify(call: WriteNode): boolean {
    const { callee } = call;
    return (
        callee?.type === "MemberExpression" &&
        identName(callee.object) === "JSON" &&
        identName(callee.property) === "stringify"
    );
};

const stringValue = function stringValue(node: WriteNode | undefined): string | null {
    return node?.type === "Literal" && typeof node.value === "string" ? node.value : null;
};

export const parentWriteMissingUtf8 = function parentWriteMissingUtf8(call: WriteNode): boolean {
    const { parent } = call;
    if (parent?.type !== "CallExpression" || parent.callee?.type !== "MemberExpression") {
        return false;
    }
    if (!WRITE_METHODS.has(identName(parent.callee.property) ?? "")) {
        return false;
    }
    return !(parent.arguments ?? []).some((arg) => encodingOf(stringValue(arg) ?? "") === UTF8);
};

export const isFileWriteCall = function isFileWriteCall(node: WriteNode | undefined): boolean {
    return node?.type === "CallExpression" && FILE_WRITE_FNS.has(calledName(node) ?? "");
};
```
