# tools/core/transformers/scope.transformer.ts

> 74 lines of code and 16 definitions.

Tree: Coordination tree
Language: typescript
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-transformers-scope-transformer-ts
Source text: https://banes-lab.com/assets/sources/source.30e30e486172f9f671775d756fdd39baf100cabe11193c12d622787ec41f452a.generated.txt

## Definitions

- `isSafe` (lexical_declaration, line 7)
- `encodeScope` (lexical_declaration, line 46, exported)
- `decodeScope` (lexical_declaration, line 63, exported)
- `hexOf` (lexical_declaration, line 20)
- `ESCAPE` (lexical_declaration, line 1)
- `HEX` (lexical_declaration, line 3)
- `RADIX` (lexical_declaration, line 5)
- `left` (lexical_declaration, line 22)
- `valueOf` (lexical_declaration, line 32)
- `at` (lexical_declaration, line 36)
- `digits` (lexical_declaration, line 56, exported)
- `out` (lexical_declaration, line 64, exported)
- `index` (lexical_declaration, line 65, exported)
- `character` (lexical_declaration, line 68, exported)
- `width` (lexical_declaration, line 79, exported)
- `code` (lexical_declaration, line 84, exported)

## Used by

- [tools/core/reporters/rule.reporter.ts](https://banes-lab.com/source/coordination/tools/core/reporters/rule.reporter.ts.md)

## Source

```typescript
const ESCAPE = "~";

const HEX = "0123456789abcdef";

const RADIX = 16;

const isSafe = function isSafe(character: string): boolean {
    if (character >= "a" && character <= "z") {
        return true;
    }
    if (character >= "A" && character <= "Z") {
        return true;
    }
    if (character >= "0" && character <= "9") {
        return true;
    }
    return character === "-";
};

const hexOf = function hexOf(code: number): string {
    let out = "";
    let left = code;

    while (left > 0) {
        out = `${HEX.charAt(left % RADIX)}${out}`;
        left = Math.floor(left / RADIX);
    }

    return out.length === 0 ? "0" : out;
};

const valueOf = function valueOf(digits: string): number {
    let out = 0;

    for (const digit of digits) {
        const at = HEX.indexOf(digit);
        if (at === -1) {
            return -1;
        }
        out = out * RADIX + at;
    }

    return out;
};

export const encodeScope = function encodeScope(scope: string): string {
    let out = "";

    for (const character of scope) {
        if (isSafe(character) && character !== ESCAPE) {
            out += character;
            continue;
        }

        const code = character.codePointAt(0) ?? 0;
        const digits = hexOf(code);
        out += `${ESCAPE}${hexOf(digits.length)}${digits}`;
    }

    return out;
};

export const decodeScope = function decodeScope(encoded: string): string | null {
    let out = "";
    let index = 0;

    while (index < encoded.length) {
        const character = encoded.charAt(index);

        if (character !== ESCAPE) {
            if (!isSafe(character)) {
                return null;
            }
            out += character;
            index += 1;
            continue;
        }

        const width = valueOf(encoded.charAt(index + 1));
        if (width <= 0 || index + 2 + width > encoded.length) {
            return null;
        }

        const code = valueOf(encoded.slice(index + 2, index + 2 + width));
        if (code < 0) {
            return null;
        }

        out += String.fromCodePoint(code);
        index += 2 + width;
    }

    return out;
};
```
