# core/converters/access.converter.ts

> 40 lines of code and 10 definitions.

Tree: GovLab Quality
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-converters-access-converter-ts
Source text: https://banes-lab.com/source/quality/core/converters/access.converter.ts.txt

Listed in [core/converters](https://banes-lab.com/api/source/quality/core/converters.md), before [core/converters/canon.concept.converter.ts](https://banes-lab.com/source/quality/core/converters/canon.concept.converter.ts.md).

## Definitions

- `accessAt` (lexical_declaration, line 7)
- `editsFor` (lexical_declaration, line 31)
- `visit` (lexical_declaration, line 9)
- `bracketAccess` (lexical_declaration, line 41, exported)
- `LINE_BASE` (lexical_declaration, line 4)
- `PROBE_NAME` (lexical_declaration, line 5)
- `result` (lexical_declaration, line 8)
- `editFor` (lexical_declaration, line 26)
- `optional` (lexical_declaration, line 27)
- `source` (lexical_declaration, line 32)

## Contained in

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

## Linked from

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

## Source

```typescript
import type { AccessEdit, AccessHit } from "#types/access.types";
import ts from "typescript";

const LINE_BASE = 1;
const PROBE_NAME = "index-access.ts";

const accessAt = function accessAt(source: ts.SourceFile, position: number): ts.PropertyAccessExpression | null {
    let result: ts.PropertyAccessExpression | null = null;
    const visit = function visit(node: ts.Node): void {
        if (position < node.getStart(source) || position >= node.getEnd()) {
            return;
        }
        if (
            ts.isPropertyAccessExpression(node) &&
            node.name.getStart(source) <= position &&
            position < node.name.getEnd()
        ) {
            result = node;
        }
        node.forEachChild(visit);
    };
    visit(source);
    return result;
};

const editFor = function editFor(access: ts.PropertyAccessExpression): AccessEdit {
    const optional = access.questionDotToken ? "?." : "";
    return { end: access.name.getEnd(), start: access.expression.getEnd(), text: `${optional}["${access.name.text}"]` };
};

const editsFor = function editsFor(text: string, hits: readonly AccessHit[]): AccessEdit[] {
    const source = ts.createSourceFile(PROBE_NAME, text, ts.ScriptTarget.Latest, true);
    return hits
        .map((hit) =>
            accessAt(source, source.getPositionOfLineAndCharacter(hit.line - LINE_BASE, hit.column - LINE_BASE)),
        )
        .filter((access): access is ts.PropertyAccessExpression => access !== null)
        .map(editFor);
};

export const bracketAccess = function bracketAccess(text: string, hits: readonly AccessHit[]): string {
    return editsFor(text, hits)
        .toSorted((left, right) => right.start - left.start)
        .reduce((acc, edit) => acc.slice(0, edit.start) + edit.text + acc.slice(edit.end), text);
};
```
