# core/converters/identifier.converter.ts

> 46 lines of code and 10 definitions.

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

Listed in [core/converters](https://banes-lab.com/api/source/context/core/converters.md), after [core/converters/check.converter.ts](https://banes-lab.com/source/context/core/converters/check.converter.ts.md) and before [core/converters/text.converter.ts](https://banes-lab.com/source/context/core/converters/text.converter.ts.md).

## Definitions

- `slugify` (lexical_declaration, line 38, exported)
- `nameKeyOf` (lexical_declaration, line 47, exported)
- `inRange` (lexical_declaration, line 12)
- `isAlnum` (lexical_declaration, line 16)
- `appended` (lexical_declaration, line 28)
- `SPACE` (lexical_declaration, line 10)
- `SlugState` (interface_declaration, line 23)
- `lowered` (lexical_declaration, line 39, exported)
- `state` (lexical_declaration, line 40, exported)
- `at` (lexical_declaration, line 41, exported)

## Contained in

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

## Used by

- [core/analyzers/algorithm.analyzer.ts](https://banes-lab.com/source/context/core/analyzers/algorithm.analyzer.ts.md)
- [core/normalizers/algorithm.normalizer.ts](https://banes-lab.com/source/context/core/normalizers/algorithm.normalizer.ts.md)
- [core/normalizers/architecture.normalizer.ts](https://banes-lab.com/source/context/core/normalizers/architecture.normalizer.ts.md)
- [core/normalizers/lexicon.normalizer.ts](https://banes-lab.com/source/context/core/normalizers/lexicon.normalizer.ts.md)
- [core/predicates/field.predicate.ts](https://banes-lab.com/source/context/core/predicates/field.predicate.ts.md)
- [core/resolvers/layer.resolver.ts](https://banes-lab.com/source/context/core/resolvers/layer.resolver.ts.md)
- [core/stores/architecture.store.ts](https://banes-lab.com/source/context/core/stores/architecture.store.ts.md)
- [core/stores/lexicon.store.ts](https://banes-lab.com/source/context/core/stores/lexicon.store.ts.md)
- [core/validators/alias.validator.ts](https://banes-lab.com/source/context/core/validators/alias.validator.ts.md)
- [core/validators/architecture.validator.ts](https://banes-lab.com/source/context/core/validators/architecture.validator.ts.md)
- [core/validators/kind.validator.ts](https://banes-lab.com/source/context/core/validators/kind.validator.ts.md)
- [core/validators/record.validator.ts](https://banes-lab.com/source/context/core/validators/record.validator.ts.md)

## Linked from

- [core/analyzers](https://banes-lab.com/anatomy/context/folder-context-core-analyzers.md)
- [core/converters](https://banes-lab.com/anatomy/context/folder-context-core-converters.md)
- [core/normalizers](https://banes-lab.com/anatomy/context/folder-context-core-normalizers.md)
- [core/predicates](https://banes-lab.com/anatomy/context/folder-context-core-predicates.md)
- [core/resolvers](https://banes-lab.com/anatomy/context/folder-context-core-resolvers.md)
- [core/stores](https://banes-lab.com/anatomy/context/folder-context-core-stores.md)
- [core/validators](https://banes-lab.com/anatomy/context/folder-context-core-validators.md)

## Source

```typescript
import {
    DIGIT_END,
    DIGIT_START,
    LOWER_END,
    LOWER_START,
    SLUG_SEPARATOR,
} from "#configuration/constants/identifier.constants";
import { identifierParts, normalizeWord } from "@govlab/constants";

const SPACE = " ";

const inRange = function inRange(code: number, start: number, end: number): boolean {
    return code >= start && code <= end;
};

const isAlnum = function isAlnum(code: number | undefined): boolean {
    if (typeof code !== "number") {
        return false;
    }
    return inRange(code, DIGIT_START, DIGIT_END) || inRange(code, LOWER_START, LOWER_END);
};

interface SlugState {
    out: string;
    prevHyphen: boolean;
}

const appended = function appended(state: SlugState, ch: string): SlugState {
    if (isAlnum(ch.codePointAt(0))) {
        return { out: state.out + ch, prevHyphen: false };
    }
    if (state.prevHyphen || state.out.length === 0) {
        return state;
    }
    return { out: `${state.out}${SLUG_SEPARATOR}`, prevHyphen: true };
};

export const slugify = function slugify(name: string): string {
    const lowered = name.toLowerCase();
    let state: SlugState = { out: "", prevHyphen: false };
    for (let at = 0; at < lowered.length; at += 1) {
        state = appended(state, lowered.charAt(at));
    }
    return state.out.endsWith(SLUG_SEPARATOR) ? state.out.slice(0, -1) : state.out;
};

export const nameKeyOf = function nameKeyOf(phrase: string): string {
    return slugify(identifierParts(phrase).join(SPACE))
        .split(SLUG_SEPARATOR)
        .filter((word) => word.length > 0)
        .map((word) => normalizeWord(word))
        .join(SLUG_SEPARATOR);
};
```
