# core/analyzers/tone.analyzer.ts

> 43 lines of code and 9 definitions.

Tree: Build tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/build#file-build-core-analyzers-tone-analyzer-ts
Source text: https://banes-lab.com/assets/sources/source.16493d2949bdc53f2ed3887560879d07e96ca2547e765e08bf7d9fed15af407b.generated.txt

## Definitions

- `countPersons` (lexical_declaration, line 10)
- `occurrences` (lexical_declaration, line 14)
- `measureLiterals` (lexical_declaration, line 24, exported)
- `count` (lexical_declaration, line 15)
- `from` (lexical_declaration, line 16)
- `joined` (lexical_declaration, line 25, exported)
- `lower` (lexical_declaration, line 26, exported)
- `words` (lexical_declaration, line 27, exported)
- `shapes` (lexical_declaration, line 28, exported)

## Uses

- [core/normalizers/word.normalizer.ts](https://banes-lab.com/source/build/core/normalizers/word.normalizer.ts.md)

## Source

```typescript
import { COLLECTIVE_PERSON, FIRST_PERSON, SECOND_PERSON } from "#configuration/constants/tone.constants";
import { LONG_DASH, METRIC_UNITS, SEMICOLON } from "@ssot/govlab/shared/manifests/punctuation.manifest.ts";
import { countAny, digitMetricsOf, lowerWordsOf } from "#core/normalizers/word.normalizer";
import { longestOf, shapesOf } from "@ssot/govlab/shared/analyzers/sentence.analyzer.ts";
import { BANNED_TERMS } from "@ssot/govlab/shared/manifests/vocabulary.manifest.ts";
import { JOIN_CAP } from "@ssot/govlab/shared/manifests/sentence.manifest.ts";
import type { ToneMetrics } from "#types/tone.types";
import { isLabelledItem } from "#core/normalizers/sentence.normalizer";

const countPersons = function countPersons(words: readonly string[], markers: ReadonlySet<string>): number {
    return words.filter((word) => markers.has(word)).length;
};

const occurrences = function occurrences(text: string, needle: string): number {
    let count = 0;
    let from = text.indexOf(needle);
    while (from !== -1) {
        count += 1;
        from = text.indexOf(needle, from + needle.length);
    }
    return count;
};

export const measureLiterals = function measureLiterals(module: string, literals: readonly string[]): ToneMetrics {
    const joined = literals.join(" ");
    const lower = joined.toLowerCase();
    const words = lowerWordsOf(joined);
    const shapes = literals.flatMap(shapesOf);
    return {
        agentlessPassives: shapes.filter((shape) => shape.agentlessPassive).length,
        bannedTerms: countAny(lower, BANNED_TERMS),
        chainedSentences: shapes.filter((shape) => shape.joins > JOIN_CAP).length,
        collectivePerson: countPersons(words, COLLECTIVE_PERSON),
        digitMetrics: digitMetricsOf(lower, METRIC_UNITS),
        firstPerson: countPersons(words, FIRST_PERSON),
        labelledItems: literals.filter(isLabelledItem).length,
        literals: literals.length,
        longDashes: occurrences(joined, LONG_DASH),
        longestSentence: longestOf(shapes),
        module,
        secondPerson: countPersons(words, SECOND_PERSON),
        semicolons: occurrences(joined, SEMICOLON),
        sentences: shapes.length,
        words: words.length,
    };
};
```
