Skip to content

Commit

Permalink
add withTrim, withReplace and update the types of enum / value() for …
Browse files Browse the repository at this point in the history
…convenience
  • Loading branch information
rawpixel-vincent committed Mar 5, 2024
1 parent 8ac8d05 commit 2cfa5fc
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 8 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ The StringList class extends the Array interface types to work with string liter
- `withSuffix($)`: add suffix to all the words.
- `withDerivatedPrefix($)` and `withDerivatedSuffix($)`: Generate words variants with or without the given suffix/prefix depending on their presence.
- `value($)`: similar to enum but throws an error if the value doesn't exists.
- `enum` Object is exposed as readonly.
- `withTrim()`: trim all the words.
- `withReplace(search, replacement)`: call the String.prototype.replace on all the words.
- `withReplaceAll(search, replacement)`: call the String.prototype.replaceAll on all the words.

## Installation

Expand Down Expand Up @@ -68,6 +72,10 @@ v.value('not') => throws;

v.withDerivatedSuffix('s') => SL<"foo" | "foos" | "bars" "bar">;
v.withDerivatedPrefix('#') => SL<"foo" | "#foo" | "bar" | "#bar">;

v.withTrim() => SL<"foo" | "bar">;
v.withReplace('a', 'e') => SL<"foo" | "ber">;
v.withReplaceAll('o', 'e') => SL<"fee" | "bar">;
```

```js
Expand Down Expand Up @@ -113,6 +121,8 @@ foods.withDerivatedSuffix('s'); => SL<"food" | "bars" | "pasta" | "meatballs" |

const tags = stringList('spring', '#boot', '#typescript', 'fundamentals');
tags.withDerivatedPrefix('#'); => SL<"#spring" | "#boot" | "#typescript" | "#fundamentals" | "spring" | "boot" | "typescript" | "fundamentals">

const scored = stringList('if has ', 'spaces', ' between ', ' o r', 'into the words').withTrim().withReplaceAll(' ', '_') => SL<"if_has" | "spaces" | "between" | "o_r" |"into_the_words">
```

#### list.concat(...(string|StringList)[])
Expand Down
13 changes: 11 additions & 2 deletions StringLiteralList.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,16 @@ export interface IStringList<T extends string>
withDerivatedPrefix<S extends string>(
chars: S
): IStringList<T | sl.utils.DropPrefix<sl.utils.DropPrefix<sl.utils.StringConcat<sl.utils.StringConcat<S, S>, T>, S>, sl.utils.StringConcat<S, S>>>;
value<V = T>(val: V): V extends T ? V : never;
withReplace<
S extends string | RegExp,
D extends string
>(searchValue: S, replaceValue: D): IStringList<sl.utils.Replace<T, S, D>>;
withReplaceAll<
S extends string | RegExp,
D extends string
>(searchValue: S, replaceValue: D): IStringList<sl.utils.ReplaceAll<T, S, D>>;
withTrim(): IStringList<sl.utils.Trim<T>>;
value(val): T;
mutable(): T & string[];
sort<P1 = T, P2 = T>(compareFn?: (a: P1, b: P2) => number): this;
reverse(): this;
Expand All @@ -36,7 +45,7 @@ export interface IStringList<T extends string>
// Readonly overrides
readonly length: number;
readonly [n: number]: T | undefined;
readonly enum: { [P in T & string]: P };
readonly enum: { [P in T & string]: P } & Omit<{ [P in number | string | symbol]: P extends number | symbol ? never : T | undefined | null }, T>;

// Supported Methods
at(n: number): T | undefined;
Expand Down
44 changes: 38 additions & 6 deletions StringLiteralList.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,22 @@ import 'core-js/actual/array/with.js';
export class SL extends Array {
literal = undefined;
enum;
hasEmpty = false;
constructor(...args) {
super(...args);
this.enum = Object.freeze(Object.fromEntries(this.map((v) => [v, v])));
this.enum = Object.fromEntries(
this.map((v) => {
if (v === '') {
this.hasEmpty = true;
}
return [v, v];
}),
);

if (this.hasEmpty) {
this.enum[''] = '';
}
Object.freeze(this.enum);
}

concat(...args) {
Expand All @@ -27,15 +40,19 @@ export class SL extends Array {
return Object.freeze(new SL(...super.slice.apply(this, arguments)));
}

withPrefix(prefix) {
withTrim() {
return Object.freeze(new SL(...super.map((e) => e.trim())));
}

withPrefix(prefix = '') {
return Object.freeze(new SL(...super.map((e) => `${prefix}${e}`)));
}

withSuffix(suffix) {
withSuffix(suffix = '') {
return Object.freeze(new SL(...super.map((e) => `${e}${suffix}`)));
}

withDerivatedSuffix(chars) {
withDerivatedSuffix(chars = '') {
return Object.freeze(
new SL(
...super.flatMap((t) => [
Expand All @@ -48,7 +65,7 @@ export class SL extends Array {
);
}

withDerivatedPrefix(chars) {
withDerivatedPrefix(chars = '') {
return Object.freeze(
new SL(
...super.flatMap((t) => [
Expand All @@ -61,8 +78,23 @@ export class SL extends Array {
);
}

withReplace(string, replacement = '') {
return Object.freeze(
new SL(...super.map((e) => e.replace(string, replacement))),
);
}

withReplaceAll(string, replacement = '') {
return Object.freeze(
new SL(...super.map((e) => e.replaceAll(string, replacement))),
);
}

value(value) {
if (this.enum[value]) {
if (
typeof value === 'string' &&
(this.enum[value] || (this.hasEmpty && value === ''))
) {
return value;
}
throw new Error(`Invalid value ${value}`);
Expand Down
34 changes: 34 additions & 0 deletions stringList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,40 @@ t.test("withSuffix('.suffix')", (t) => {
t.end();
});

t.test('withReplace("1")', (t) => {
const list = stringList('f1oo', 'b1ar').withReplace('1', '');
testExpectedArrayValues(t, list, 'foo', 'bar');
testEscapingFromStringList(t, list, 'foo', 'bar');
t.end();
});

t.test('withReplaceAll("z")', (t) => {
const list = stringList('foo', 'azzztiv', 'zzz', 'z1').withReplaceAll(
'z',
'',
);
testExpectedArrayValues(t, list, 'foo', 'ativ', '', '1');
testEscapingFromStringList(t, list, 'foo', 'ativ', '', '1');
t.end();
});

t.test('withTrim()', (t) => {
const list = stringList(' foo ', ' bar ').withTrim();
testExpectedArrayValues(t, list, 'foo', 'bar');
testEscapingFromStringList(t, list, 'foo', 'bar');
t.end();
});

t.test('withTrim().withReplaceAll("_")', (t) => {
const list = stringList('has spaces ', ' has more_spaces')
.withTrim()
.withReplaceAll(' ', '_');
testExpectedArrayValues(t, list, 'has_spaces', 'has_more_spaces');
testEscapingFromStringList(t, list, 'has_spaces', 'has_more_spaces');

t.end();
});

t.test("concat('zing', 'boom')", (t) => {
const list = stringList('foo', 'bar').concat('zing', 'boom');
testExpectedArrayValues(t, list, 'foo', 'bar', 'zing', 'boom');
Expand Down
13 changes: 13 additions & 0 deletions types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { ArrayInPlaceMutation } from './StringLiteralList.js';

export namespace sl {
export namespace utils {
type IsStringLiteral<T extends string> = [T] extends [string] ? [string] extends [T] ? false : Uppercase<T> extends Uppercase<Lowercase<T>> ? Lowercase<T> extends Lowercase<Uppercase<T>> ? true : false : false : false;

export type StringConcat<
T1 extends string | number | bigint | boolean,
T2 extends string | number | bigint | boolean,
Expand All @@ -24,6 +26,17 @@ export namespace sl {
: sentence extends `${prefix}${infer rest}`
? rest
: sentence;


type TrimStart<T extends string> = IsStringLiteral<T> extends true ? T extends ` ${infer rest}` ? TrimStart<rest> : T : string;

type TrimEnd<T extends string> = IsStringLiteral<T> extends true ? T extends `${infer rest} ` ? TrimEnd<rest> : T : string;

type Trim<T extends string> = TrimEnd<TrimStart<T>>;

type Replace<sentence extends string, lookup extends string | RegExp, replacement extends string = ''> = lookup extends string ? IsStringLiteral<lookup | sentence | replacement> extends true ? sentence extends `${infer rest}${lookup}${infer rest2}` ? `${rest}${replacement}${rest2}` : sentence : string : string;

type ReplaceAll<sentence extends string, lookup extends string | RegExp, replacement extends string = ''> = lookup extends string ? IsStringLiteral<lookup | sentence | replacement> extends true ? sentence extends `${infer rest}${lookup}${infer rest2}` ? `${rest}${replacement}${ReplaceAll<rest2, lookup, replacement>}` : sentence : string : string;
}

export namespace specs {
Expand Down

0 comments on commit 2cfa5fc

Please sign in to comment.