From efaacb53e2172bacb1ffa974b2d0ad52a53f6205 Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:37:59 -0700 Subject: [PATCH 01/10] feat: reify filter method --- src/list/{filter.spec.ts => filter.test.ts} | 18 +++++++++++++++++- src/list/filter.ts | 20 +++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) rename src/list/{filter.spec.ts => filter.test.ts} (69%) diff --git a/src/list/filter.spec.ts b/src/list/filter.test.ts similarity index 69% rename from src/list/filter.spec.ts rename to src/list/filter.test.ts index fc6e0cb62..bfc1d9eaa 100644 --- a/src/list/filter.spec.ts +++ b/src/list/filter.test.ts @@ -1,4 +1,4 @@ -import { $, Conditional, Function, Kind, List, Test } from '..' +import { $, Conditional, Function, Kind, List, NaturalNumber, Test } from '..' type Filter_Spec = [ /** @@ -58,3 +58,19 @@ type Filter_Spec = [ [1, 2, 3] > ] + +it('should not filter out when predicate always returns true', () => { + expect(List.filter(Function.constant(true))([1, 2, 3, 4, 5])).toEqual([ + 1, 2, 3, 4, 5 + ]) +}) + +it('should filter out when predicate always returns false', () => { + expect(List.filter(Function.constant(false))([1, 2, 3, 4, 5])).toEqual([]) +}) + +it('can filter out numbers that are not greater than 3', () => { + expect(List.filter(NaturalNumber.isGreaterThan(3))([1, 2, 3, 4, 5])).toEqual([ + 4, 5 + ]) +}) diff --git a/src/list/filter.ts b/src/list/filter.ts index ad5ced979..0984bebd6 100644 --- a/src/list/filter.ts +++ b/src/list/filter.ts @@ -1,4 +1,4 @@ -import { $, Type, Kind } from '..' +import { $, Type, Kind, Function } from '..' /** * `_$filter` is a type-level function that takes in two inputs: @@ -82,3 +82,21 @@ export interface Filter extends Kind.Kind { x: Type._$cast boolean>> ): Filter_T } + +/** + * Given a predicate and a list, filter the list to only include elements that + * satisfy the predicate. + * + * @param {Kind.Kind<(x: never) => boolean>} f - The predicate to filter the list by. + * @param {unknown[]} values - The list to filter. + * + * @example + * ```ts + * import { List, String } from "hkt-toolbelt"; + * + * const result = List.filter(NaturalNumber.isGreaterThan(3))([1, 2, 3, 4, 5]) + * // ^? [4, 5] + * ``` + */ +export const filter = ((f: Function.Function) => (values: unknown[]) => + values.filter((value) => f(value as never))) as Kind._$reify From 49e8ca76cdeb0af1661cb4d3b007d58533d9356a Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:38:08 -0700 Subject: [PATCH 02/10] feat: reify subtract-by method --- ...subtract-by.spec.ts => subtract-by.test.ts} | 8 ++++++++ src/natural-number/subtract-by.ts | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) rename src/natural-number/{subtract-by.spec.ts => subtract-by.test.ts} (86%) diff --git a/src/natural-number/subtract-by.spec.ts b/src/natural-number/subtract-by.test.ts similarity index 86% rename from src/natural-number/subtract-by.spec.ts rename to src/natural-number/subtract-by.test.ts index 234485fd4..d8e7baefd 100644 --- a/src/natural-number/subtract-by.spec.ts +++ b/src/natural-number/subtract-by.test.ts @@ -51,3 +51,11 @@ type SubtractBy_Spec = [ */ Test.Expect<$<$, 123>, 0> ] + +it('should subtract two numbers', () => { + expect(NaturalNumber.subtractBy(123)(456)).toBe(333) +}) + +it('caps result at zero', () => { + expect(NaturalNumber.subtractBy(456)(123)).toBe(0) +}) diff --git a/src/natural-number/subtract-by.ts b/src/natural-number/subtract-by.ts index bb3d3bd79..4650aac40 100644 --- a/src/natural-number/subtract-by.ts +++ b/src/natural-number/subtract-by.ts @@ -46,3 +46,21 @@ export interface SubtractBy extends Kind.Kind { x: Type._$cast ): Number._$isNatural extends true ? SubtractBy_T : never } + +/** + * Given two natural numbers, subtract the first number from the second. The + * result is capped at zero. + * + * @param {number} a - The first number. + * @param {number} b - The second number. + * + * @example + * ```ts + * import { NaturalNumber } from "hkt-toolbelt"; + * + * const result = NaturalNumber.subtractBy(2)(3) + * // ^? 1 + * ``` + */ +export const subtractBy = ((a: number) => (b: number) => + a > b ? 0 : b - a) as Kind._$reify From d81f164a4edca1fcf78496137fd1473867b56a8b Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:38:17 -0700 Subject: [PATCH 03/10] feat: reify subtract method --- .../{subtract.spec.ts => subtract.test.ts} | 8 ++++++++ src/natural-number/subtract.ts | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) rename src/natural-number/{subtract.spec.ts => subtract.test.ts} (86%) diff --git a/src/natural-number/subtract.spec.ts b/src/natural-number/subtract.test.ts similarity index 86% rename from src/natural-number/subtract.spec.ts rename to src/natural-number/subtract.test.ts index 99aa52150..fad464770 100644 --- a/src/natural-number/subtract.spec.ts +++ b/src/natural-number/subtract.test.ts @@ -51,3 +51,11 @@ type Subtract_Spec = [ */ Test.Expect<$<$, 456>, 0> ] + +it('should subtract two numbers', () => { + expect(NaturalNumber.subtract(456)(123)).toBe(333) +}) + +it('result is capped at zero', () => { + expect(NaturalNumber.subtract(123)(456)).toBe(0) +}) diff --git a/src/natural-number/subtract.ts b/src/natural-number/subtract.ts index 27c125245..d91176448 100644 --- a/src/natural-number/subtract.ts +++ b/src/natural-number/subtract.ts @@ -81,3 +81,20 @@ export interface Subtract extends Kind.Kind { x: Type._$cast ): Number._$isNatural extends true ? Subtract_T : never } + +/** + * Given two natural numbers, subtract the second number from the first. + * + * @param {number} a - The first number. + * @param {number} b - The second number. + * + * @example + * ```ts + * import { NaturalNumber } from "hkt-toolbelt"; + * + * const result = NaturalNumber.subtract(3)(2) + * // ^? 1 + * ``` + */ +export const subtract = ((a: number) => (b: number) => + b > a ? 0 : a - b) as Kind._$reify From 1f94f939e51e1d057745c7499c593c95b288b2f2 Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:38:28 -0700 Subject: [PATCH 04/10] feat: add from-char-code method --- src/string/from-char-code.test.ts | 33 +++++++ src/string/from-char-code.ts | 154 ++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 src/string/from-char-code.test.ts create mode 100644 src/string/from-char-code.ts diff --git a/src/string/from-char-code.test.ts b/src/string/from-char-code.test.ts new file mode 100644 index 000000000..c43a4435e --- /dev/null +++ b/src/string/from-char-code.test.ts @@ -0,0 +1,33 @@ +import { $, String, Test } from '..' + +type FromCharCode_Spec = [ + /** + * Can get the character of a character code. + */ + Test.Expect<$, 'f'>, + + /** + * Can get the character of a space. + */ + Test.Expect<$, ' '>, + + /** + * An empty string results in never. + */ + Test.Expect<$, never>, + + /** + * Non-number input results in a compiler error. + */ + // @ts-expect-error + $, + + /** + * Non-ASCII characters result in never + */ + Test.Expect<$, never> +] + +it('should return the character of a character code', () => { + expect(String.fromCharCode(102)).toBe('f') +}) diff --git a/src/string/from-char-code.ts b/src/string/from-char-code.ts new file mode 100644 index 000000000..d6dd07476 --- /dev/null +++ b/src/string/from-char-code.ts @@ -0,0 +1,154 @@ +import { Kind, Type } from '..' + +type _$charCodeMapInverse = { + 97: 'a' + 98: 'b' + 99: 'c' + 100: 'd' + 101: 'e' + 102: 'f' + 103: 'g' + 104: 'h' + 105: 'i' + 106: 'j' + 107: 'k' + 108: 'l' + 109: 'm' + 110: 'n' + 111: 'o' + 112: 'p' + 113: 'q' + 114: 'r' + 115: 's' + 116: 't' + 117: 'u' + 118: 'v' + 119: 'w' + 120: 'x' + 121: 'y' + 122: 'z' + 65: 'A' + 66: 'B' + 67: 'C' + 68: 'D' + 69: 'E' + 70: 'F' + 71: 'G' + 72: 'H' + 73: 'I' + 74: 'J' + 75: 'K' + 76: 'L' + 77: 'M' + 78: 'N' + 79: 'O' + 80: 'P' + 81: 'Q' + 82: 'R' + 83: 'S' + 84: 'T' + 85: 'U' + 86: 'V' + 87: 'W' + 88: 'X' + 89: 'Y' + 90: 'Z' + 48: '0' + 49: '1' + 50: '2' + 51: '3' + 52: '4' + 53: '5' + 54: '6' + 55: '7' + 56: '8' + 57: '9' + 32: ' ' + 33: '!' + 34: '"' + 35: '#' + 36: '$' + 37: '%' + 38: '&' + 39: "'" + 40: '(' + 41: ')' + 42: '*' + 43: '+' + 44: ',' + 45: '-' + 46: '.' + 47: '/' + 58: ':' + 59: ';' + 60: '<' + 61: '=' + 62: '>' + 63: '?' + 64: '@' + 91: '[' + 92: '\\' + 93: ']' + 94: '^' + 95: '_' + 96: '`' + 123: '{' + 124: '|' + 125: '}' + 126: '~' + 9: '\t' + 10: '\n' + 13: '\r' + 12: '\f' + 11: '\v' +} + +/** + * `_$fromCharCode` is a type-level function that takes in a number `N` and + * returns the character corresponding to that character code. This is only valid + * for ASCII character codes. + * + * @template {number} N - The character code to get the character for. + * + * @example + * ``` + * type T0 = _$fromCharCode<102> // 'f' + * type T1 = _$fromCharCode<98> // 'b' + * ``` + */ +export type _$fromCharCode = + N extends keyof _$charCodeMapInverse ? _$charCodeMapInverse[N] : never + +/** + * `FromCharCode` is a type-level function that takes in a number `N` and + * returns the character corresponding to that character code. This is only valid + * for ASCII character codes. + * + * @template {number} N - The character code to get the character for. + * + * @example + * ```ts + * import { $, String } from "hkt-toolbelt"; + * + * type Result = $ // 'f' + * ``` + */ +export interface FromCharCode extends Kind.Kind { + f(x: Type._$cast): _$fromCharCode +} + +/** + * Given a character code, return the corresponding character. + * + * @param {number} x - The character code to get the character for. + * + * @example + * ```ts + * import { String } from "hkt-toolbelt"; + * + * const result = String.fromCharCode(102) + * // ^? 'f' + * ``` + */ +export const fromCharCode = ((x: number) => + String.fromCharCode(x)) as Kind._$reify From f6dcebcbe67195e75c8d92793f6eb37506b28e18 Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:38:36 -0700 Subject: [PATCH 05/10] feat: add is-letter method --- src/string/is-letter.test.ts | 31 +++++++++++ src/string/is-letter.ts | 100 +++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/string/is-letter.test.ts create mode 100644 src/string/is-letter.ts diff --git a/src/string/is-letter.test.ts b/src/string/is-letter.test.ts new file mode 100644 index 000000000..a35ab4a2c --- /dev/null +++ b/src/string/is-letter.test.ts @@ -0,0 +1,31 @@ +import { $, String, Test } from '..' + +type IsLetter_Spec = [ + /** + * Can check if a string is a letter. + */ + Test.Expect<$, true>, + + /** + * Can check if a string is not a letter. + */ + Test.Expect<$, false>, + + /** + * An empty string is not a letter. + */ + Test.Expect<$, false>, + + /** + * A template literal string is not a letter. + */ + Test.Expect<$, false> +] + +it('should check if a string is a letter', () => { + expect(String.isLetter('f')).toBe(true) +}) + +it('returns false for an empty string', () => { + expect(String.isLetter('')).toBe(false) +}) diff --git a/src/string/is-letter.ts b/src/string/is-letter.ts new file mode 100644 index 000000000..e2a11e595 --- /dev/null +++ b/src/string/is-letter.ts @@ -0,0 +1,100 @@ +import { Kind, Type } from '..' + +type _$letter = + | 'a' + | 'b' + | 'c' + | 'd' + | 'e' + | 'f' + | 'g' + | 'h' + | 'i' + | 'j' + | 'k' + | 'l' + | 'm' + | 'n' + | 'o' + | 'p' + | 'q' + | 'r' + | 's' + | 't' + | 'u' + | 'v' + | 'w' + | 'x' + | 'y' + | 'z' + | 'A' + | 'B' + | 'C' + | 'D' + | 'E' + | 'F' + | 'G' + | 'H' + | 'I' + | 'J' + | 'K' + | 'L' + | 'M' + | 'N' + | 'O' + | 'P' + | 'Q' + | 'R' + | 'S' + | 'T' + | 'U' + | 'V' + | 'W' + | 'X' + | 'Y' + | 'Z' + +/** + * `_$isLetter` is a type-level function that checks if + * + * @template {string} S - The string to check. + * + * @example + * ``` + * type T0 = String._$isLetter<'f'> // true + * type T1 = String._$isLetter<'9'> // false + * ``` + */ +export type _$isLetter = S extends _$letter ? true : false + +/** + * `IsLetter` is a type-level function that checks if a string is a letter. + * + * @template {string} S - The string to check. + * + * @example + * ```ts + * import { $, String } from "hkt-toolbelt"; + * + * type Result = $ // true + * ``` + */ +export interface IsLetter extends Kind.Kind { + f(x: Type._$cast): _$isLetter +} + +/** + * Given a string, return whether or not it is a letter. + * + * @param {string} x - The string to check. + * + * @example + * ```ts + * import { String } from "hkt-toolbelt"; + * + * const result = String.isLetter('f') + * // ^? true + * ``` + */ +export const isLetter = ((x: string) => + x.match(/^[a-zA-Z]$/) !== null) as Kind._$reify From da9a05e654249fcff144af9c9684db147e736bfc Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:38:56 -0700 Subject: [PATCH 06/10] feat: reify string split method --- src/string/{split.spec.ts => split.test.ts} | 4 ++++ src/string/split.ts | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) rename src/string/{split.spec.ts => split.test.ts} (94%) diff --git a/src/string/split.spec.ts b/src/string/split.test.ts similarity index 94% rename from src/string/split.spec.ts rename to src/string/split.test.ts index b3eb05455..93295787e 100644 --- a/src/string/split.spec.ts +++ b/src/string/split.test.ts @@ -94,3 +94,7 @@ type Split_Spec = [ ] > ] + +it('should split a string into an array of substrings', () => { + expect(String.split(' ')('foo bar')).toEqual(['foo', 'bar']) +}) diff --git a/src/string/split.ts b/src/string/split.ts index faa22e562..2d9fe6eae 100644 --- a/src/string/split.ts +++ b/src/string/split.ts @@ -3,8 +3,8 @@ import { Type, Kind, String } from '..' /** * `String.Split` is a type-level function that splits a string into an array of substrings. * - * @template S - The string to split. * @template Delimiter - The delimiter to split the string by. + * @template S - The string to split. * * @example * type T0 = String._$split<'foobar', ''> // ['f', 'o', 'o', 'b', 'a', 'r'] @@ -32,8 +32,8 @@ interface Split_T extends Kind.Kind { /** * `String.Split` is a type-level function that splits a string into an array of substrings. * - * @template S - The string to split. * @template Delimiter - The delimiter to split the string by. + * @template S - The string to split. * * @example * type T0 = $<$, 'foobar'> // ['f', 'o', 'o', 'b', 'a', 'r'] @@ -42,3 +42,20 @@ interface Split_T extends Kind.Kind { export interface Split extends Kind.Kind { f(x: Type._$cast): Split_T } + +/** + * Given a string and a delimiter, split the string into an array of substrings. + * + * @param {string} d - The delimiter to split the string by. + * @param {string} s - The string to split. + * + * @example + * ```ts + * import { String } from "hkt-toolbelt"; + * + * const result = String.split(' ')('foo bar') + * // ^? ['foo', 'bar'] + * ``` + */ +export const split = ((d: string) => (s: string) => + s.split(d)) as Kind._$reify From c8d9158c5d54e3b3d2220a0c0ad62f6b08dc784b Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:39:06 -0700 Subject: [PATCH 07/10] feat: add to-char-code method --- src/string/to-char-code.test.ts | 33 +++++++ src/string/to-char-code.ts | 153 ++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 src/string/to-char-code.test.ts create mode 100644 src/string/to-char-code.ts diff --git a/src/string/to-char-code.test.ts b/src/string/to-char-code.test.ts new file mode 100644 index 000000000..b12f9d818 --- /dev/null +++ b/src/string/to-char-code.test.ts @@ -0,0 +1,33 @@ +import { $, String, Test } from '..' + +type ToCharCode_Spec = [ + /** + * Can get the character code of a string. + */ + Test.Expect<$, 102>, + + /** + * Can get the character code of a space. + */ + Test.Expect<$, 32>, + + /** + * An empty string results in never. + */ + Test.Expect<$, never>, + + /** + * Non-string input results in a compiler error. + */ + // @ts-expect-error + $, + + /** + * Non-ASCII characters result in never + */ + Test.Expect<$, never> +] + +it('should return the character code of a string', () => { + expect(String.toCharCode('f')).toBe(102) +}) diff --git a/src/string/to-char-code.ts b/src/string/to-char-code.ts new file mode 100644 index 000000000..644eb6c41 --- /dev/null +++ b/src/string/to-char-code.ts @@ -0,0 +1,153 @@ +import { Kind, Type } from '..' + +type _$charCodeMap = { + a: 97 + b: 98 + c: 99 + d: 100 + e: 101 + f: 102 + g: 103 + h: 104 + i: 105 + j: 106 + k: 107 + l: 108 + m: 109 + n: 110 + o: 111 + p: 112 + q: 113 + r: 114 + s: 115 + t: 116 + u: 117 + v: 118 + w: 119 + x: 120 + y: 121 + z: 122 + A: 65 + B: 66 + C: 67 + D: 68 + E: 69 + F: 70 + G: 71 + H: 72 + I: 73 + J: 74 + K: 75 + L: 76 + M: 77 + N: 78 + O: 79 + P: 80 + Q: 81 + R: 82 + S: 83 + T: 84 + U: 85 + V: 86 + W: 87 + X: 88 + Y: 89 + Z: 90 + '0': 48 + '1': 49 + '2': 50 + '3': 51 + '4': 52 + '5': 53 + '6': 54 + '7': 55 + '8': 56 + '9': 57 + ' ': 32 + '!': 33 + '"': 34 + '#': 35 + $: 36 + '%': 37 + '&': 38 + "'": 39 + '(': 40 + ')': 41 + '*': 42 + '+': 43 + ',': 44 + '-': 45 + '.': 46 + '/': 47 + ':': 58 + ';': 59 + '<': 60 + '=': 61 + '>': 62 + '?': 63 + '@': 64 + '[': 91 + '\\': 92 + ']': 93 + '^': 94 + _: 95 + '`': 96 + '{': 123 + '|': 124 + '}': 125 + '~': 126 + '\t': 9 + '\n': 10 + '\r': 13 + '\f': 12 + '\v': 11 +} + +/** + * `_$toCharCode` is a type-level function that takes in a string `S` and + * returns the character code of `S`. This is only valid for ASCII characters. + * + * @template {string} S - The string to get the character code of. + * + * @example + * ``` + * type T0 = _$toCharCode<'f'> // 102 + * type T1 = _$toCharCode<'b'> // 98 + * ``` + */ +export type _$toCharCode = S extends keyof _$charCodeMap + ? _$charCodeMap[S] + : never + +/** + * `ToCharCode` is a type-level function that takes in a string `S` and + * returns the character code of `S`. This is only valid for ASCII characters. + * + * @template {string} S - The string to get the character code of. + * + * @example + * ```ts + * import { $, String } from "hkt-toolbelt"; + * + * type Result = $ // 102 + * ``` + */ +export interface ToCharCode extends Kind.Kind { + f(x: Type._$cast): _$toCharCode +} + +/** + * Given a string, return the character code of the first character in the string. + * + * @param {string} x - The string to get the character code of. + * + * @example + * ```ts + * import { String } from "hkt-toolbelt"; + * + * const result = String.toCharCode('f') + * // ^? 102 + * ``` + */ +export const toCharCode = ((x: string) => + x.charCodeAt(0)) as Kind._$reify From b633c1fdf6af4bad6771bab816c0623a4954dfc2 Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:39:23 -0700 Subject: [PATCH 08/10] feat: reify to-lower method --- src/string/{to-lower.spec.ts => to-lower.test.ts} | 4 ++++ src/string/to-lower.ts | 15 +++++++++++++++ 2 files changed, 19 insertions(+) rename src/string/{to-lower.spec.ts => to-lower.test.ts} (91%) diff --git a/src/string/to-lower.spec.ts b/src/string/to-lower.test.ts similarity index 91% rename from src/string/to-lower.spec.ts rename to src/string/to-lower.test.ts index c95bce365..077a16cbe 100644 --- a/src/string/to-lower.spec.ts +++ b/src/string/to-lower.test.ts @@ -49,3 +49,7 @@ type ToLower_Spec = [ */ Test.Expect<$, Lowercase> ] + +it('should convert a string to lowercase', () => { + expect(String.toLower('FOO')).toBe('foo') +}) diff --git a/src/string/to-lower.ts b/src/string/to-lower.ts index 2af622cc3..10e65bae0 100644 --- a/src/string/to-lower.ts +++ b/src/string/to-lower.ts @@ -23,3 +23,18 @@ export type _$toLower = Lowercase export interface ToLower extends Kind.Kind { f(x: Type._$cast): _$toLower } + +/** + * Given a string, convert it to lowercase. + * + * @param {string} x - The string to convert to lowercase. + * + * @example + * ```ts + * import { String } from "hkt-toolbelt"; + * + * const result = String.toLower('HELLO') + * // ^? 'hello' + * ``` + */ +export const toLower = ((x: string) => x.toLowerCase()) as Kind._$reify From 3fe88d4a90989b9e4a0dea3f703872431e1d9458 Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:39:35 -0700 Subject: [PATCH 09/10] feat: add new string methods to index --- src/string/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/string/index.ts b/src/string/index.ts index 83fb38901..77326812d 100644 --- a/src/string/index.ts +++ b/src/string/index.ts @@ -2,9 +2,11 @@ export * from './append' export * from './capitalize' export * from './ends-with' export * from './first' +export * from './from-char-code' export * from './from-list' export * from './includes' export * from './init' +export * from './is-letter' export * from './is-string' export * from './is-template' export * from './join' @@ -17,6 +19,7 @@ export * from './slice' export * from './split' export * from './starts-with' export * from './tail' +export * from './to-char-code' export * from './to-list' export * from './to-lower' export * from './to-upper' From fd0b3bccf632beababbfd046e25ea239a114dcbd Mon Sep 17 00:00:00 2001 From: poteat Date: Fri, 4 Oct 2024 12:41:57 -0700 Subject: [PATCH 10/10] feat: add changelog for 0.24.6 --- changelog.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/changelog.md b/changelog.md index 0e9962c72..74518b9cb 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,15 @@ # Changelog +## [0.24.6] +- Add `String.FromCharCode` to convert a character code to a string. +- Add `String.IsLetter` to check if a string is a letter. +- Add `String.ToCharCode` to convert a string to a character code. +- Reify `String.Split` to a value-level function. +- Reify `String.ToLower` to a value-level function. +- Reify `NaturalNumber.SubtractBy` to a value-level function. +- Reify `NaturalNumber.Subtract` to a value-level function. +- Reify `List.Filter` to a value-level function. + ## [0.24.5] - Add `NaturalNumber.Square` to compute the square of a natural number. - Add `Object.AtKey` to get the value at a key in an object. (swapped argument order of `Object.At`)