# core/analyzers/text.analyzer.ts

> 32 lines of code and 7 definitions.

Tree: GovLab Stats
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/stats#file-stats-core-analyzers-text-analyzer-ts
Source text: https://banes-lab.com/source/stats/core/analyzers/text.analyzer.ts.txt

Listed in [core/analyzers](https://banes-lab.com/api/source/stats/core/analyzers.md), after [core/analyzers/taxonomy.analyzer.ts](https://banes-lab.com/source/stats/core/analyzers/taxonomy.analyzer.ts.md).

## Definitions

- `countLines` (lexical_declaration, line 21, exported)
- `stepLine` (lexical_declaration, line 4)
- `scan` (lexical_declaration, line 25, exported)
- `trailingEmpty` (lexical_declaration, line 29, exported)
- `total` (lexical_declaration, line 30, exported)
- `blank` (lexical_declaration, line 31, exported)
- `safeTotal` (lexical_declaration, line 32, exported)

## Contained in

- [core/analyzers](https://banes-lab.com/anatomy/stats/folder-stats-core-analyzers.md)

## Used by

- [core/analyzers/site.analyzer.ts](https://banes-lab.com/source/stats/core/analyzers/site.analyzer.ts.md)
- [core/analyzers/source.analyzer.ts](https://banes-lab.com/source/stats/core/analyzers/source.analyzer.ts.md)

## Linked from

- [core/analyzers](https://banes-lab.com/anatomy/stats/folder-stats-core-analyzers.md)

## Source

```typescript
import { INLINE_BLANKS, LINE_BREAK } from "#configuration/constants/source.constants";
import type { LineCount, LineScan } from "#types/source.types";

const stepLine = function stepLine(scan: LineScan, ch: string): LineScan {
    if (ch === LINE_BREAK) {
        return {
            blank: scan.sawNonSpace ? scan.blank : scan.blank + 1,
            runLength: 0,
            sawNonSpace: false,
            total: scan.total + 1,
        };
    }
    return {
        blank: scan.blank,
        runLength: scan.runLength + 1,
        sawNonSpace: scan.sawNonSpace || !INLINE_BLANKS.has(ch),
        total: scan.total,
    };
};

export const countLines = function countLines(text: string): LineCount {
    if (text.length === 0) {
        return { blank: 0, code: 0, total: 0 };
    }
    let scan: LineScan = { blank: 0, runLength: 0, sawNonSpace: false, total: 1 };
    for (const ch of text) {
        scan = stepLine(scan, ch);
    }
    const trailingEmpty = !scan.sawNonSpace && scan.runLength === 0;
    const total = trailingEmpty ? scan.total - 1 : scan.total;
    const blank = !scan.sawNonSpace && !trailingEmpty ? scan.blank + 1 : scan.blank;
    const safeTotal = Math.max(0, total);
    return { blank, code: safeTotal - blank, total: safeTotal };
};
```
