From 62e20cf03a5c389fb77a040c374a56d0bcfd301b Mon Sep 17 00:00:00 2001 From: Emily Marigold Klassen Date: Wed, 12 Sep 2018 14:30:45 -0700 Subject: [PATCH 1/4] doc(opts): Add documentation for other option --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 3d0591c..93e6f6b 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,24 @@ const MyAppOpts = figgyPudding({ }) ``` +##### `opts` + +###### `other(key: String) -> Boolean` + +Additional keys can be allowed, if they pass the test in this function + +###### Example + +```javascript +const MyOtherOpts = puddin({ + a: {} +}, { + other (key) { return /^special-/.test(key) } +}) +``` + +This will allow values that start with `special-` + #### `> PuddingFactory(...providers) -> FiggyPudding{}` Instantiates an options object defined by `figgyPudding()`, which uses From 65008b71e53df57b52d27bafb2511b2e60515406 Mon Sep 17 00:00:00 2001 From: Emily Marigold Klassen Date: Wed, 12 Sep 2018 14:31:38 -0700 Subject: [PATCH 2/4] feat: add typescript definitions --- index.d.ts | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + tsconfig.json | 6 +++++ 3 files changed, 79 insertions(+) create mode 100644 index.d.ts create mode 100644 tsconfig.json diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..d52c241 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,72 @@ + +declare function figgyPudding< + S extends figgyPudding.Specs = {}, + O extends figgyPudding.Options = {} +>(specs?: S, opts?: O): figgyPudding.PuddingFactory + +declare module figgyPudding { + interface Options { + other?(key: string): boolean + } + + type OtherOpt = Required> + + type Specs = { + [K in string]: string | Spec + } + interface Spec { + default?: any + } + + type SpecWithDefault = Required> + type WidenPrimitive = + T extends string ? string : + T extends number ? number : + T extends boolean ? boolean : + T + type SpecDefault = S extends {default(): infer R} ? WidenPrimitive : S extends {default: infer D} ? D : unknown + + interface MapLike { + get(key: K): V | undefined + } + + type AvailableKeys = O extends OtherOpt ? string : keyof S + + type Proxy = { + [K in keyof S]: SpecDefault + } & (O extends {other(key: string): boolean} ? { + [key: string]: unknown + } : {}) + + type ProxyFiggyPudding = Readonly> & FiggyPudding + + type PuddingFactory = (...providers: any[]) => ProxyFiggyPudding + + interface FiggyPuddingConstructor { + new ( + specs: S, opts: O, providers: any[] + ): FiggyPudding + } + + interface FiggyPudding { + readonly __isFiggyPudding: true + readonly [Symbol.toStringTag]: 'FiggyPudding' + + get>(key: K): K extends keyof S ? SpecDefault : unknown + concat

(...providers: P): ProxyFiggyPudding + toJSON(): { + [K in AvailableKeys]: K extends keyof S ? SpecDefault : unknown + } + forEach( + fn: (this: This, value: unknown, key: AvailableKeys, opts: this) => void, + thisArg?: This + ): void + entries(matcher: (key: string) => boolean): IterableIterator<[string, unknown]> + entries(): IterableIterator<[AvailableKeys, unknown]> + [Symbol.iterator](): IterableIterator<[AvailableKeys, unknown]> + keys(): IterableIterator> + values(): IterableIterator + } +} + +export = figgyPudding diff --git a/package.json b/package.json index 18145b3..b18951b 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "3.5.1", "description": "Delicious, festive, cascading config/opts definitions", "main": "index.js", + "types": "index.d.ts", "files": [ "*.js", "lib" diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..71e2b87 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "target": "es2015", + "strict": true + } +} From 69bf0b70eccbe16b246d8d55e4b2e10f0ac4d350 Mon Sep 17 00:00:00 2001 From: Emily Marigold Klassen Date: Wed, 12 Sep 2018 16:17:16 -0700 Subject: [PATCH 3/4] test(iteration): add test for omitted `thisArg --- test/iteration.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/iteration.js b/test/iteration.js index 0b05cd0..7f8ca3e 100644 --- a/test/iteration.js +++ b/test/iteration.js @@ -21,6 +21,11 @@ test('forEach', t => { [1, 'a', opts], [2, 'b', opts] ], 'correct arguments, and only declared props, in declared order') + + opts.forEach(function () { + thisArg = this + }) + t.equal(thisArg, opts, 'correct default this') t.done() }) From b929b7d529602f3ebdbc69918a8bf418e0da3ed6 Mon Sep 17 00:00:00 2001 From: Emily Marigold Klassen Date: Tue, 30 Jul 2019 19:53:33 -0700 Subject: [PATCH 4/4] idk --- index.d.ts | 9 ++- test/typedef.ts | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 test/typedef.ts diff --git a/index.d.ts b/index.d.ts index d52c241..5a2e2d5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5,6 +5,8 @@ declare function figgyPudding< >(specs?: S, opts?: O): figgyPudding.PuddingFactory declare module figgyPudding { + type Flatten = T extends [infer H] ? H : {} + interface Options { other?(key: string): boolean } @@ -38,9 +40,9 @@ declare module figgyPudding { [key: string]: unknown } : {}) - type ProxyFiggyPudding = Readonly> & FiggyPudding + type ProxyFiggyPudding = Readonly> & FiggyPudding - type PuddingFactory = (...providers: any[]) => ProxyFiggyPudding + type PuddingFactory = (...providers: T) => ProxyFiggyPudding interface FiggyPuddingConstructor { new ( @@ -53,7 +55,8 @@ declare module figgyPudding { readonly [Symbol.toStringTag]: 'FiggyPudding' get>(key: K): K extends keyof S ? SpecDefault : unknown - concat

(...providers: P): ProxyFiggyPudding + concat

(...providers: ): ProxyFiggyPudding + concat(...providers: any[]): ProxyFiggyPudding toJSON(): { [K in AvailableKeys]: K extends keyof S ? SpecDefault : unknown } diff --git a/test/typedef.ts b/test/typedef.ts new file mode 100644 index 0000000..9b49150 --- /dev/null +++ b/test/typedef.ts @@ -0,0 +1,172 @@ +import * as puddin from '../index' + +const test = (title: string, fn: (t: any) => void) => {} + +test('forEach', t => { + const testOpts = puddin({ + a: {}, + b: {} + }) + const arr = [] + let thisArg + const expectedThis = {} + const opts = testOpts({a: 1, b: 2, c: 3}) + opts.forEach(function (...args) { + thisArg = this + arr.push(args) + }, expectedThis) + t.equal(thisArg, expectedThis, 'correct thisArg') + opts.forEach(function (...args) { + thisArg = this + arr.push(args) + }) + t.equal(thisArg, opts, 'correct default this') + t.deepEqual(arr, [ + [1, 'a', opts], + [2, 'b', opts] + ], 'correct arguments, and only declared props, in declared order') + t.done() +}) + +test('entries', t => { + const testOpts = puddin({ + a: {}, + b: {} + }) + const arr = [] + const opts = testOpts({a: 1, b: 2, c: 3}) + for (let [key, value] of opts.entries()) { + arr.push([key, value]) + } + t.deepEqual(arr, [ + ['a', 1], + ['b', 2] + ], 'correct arguments, and only declared props, in declared order') + t.done() +}) + +test('entries over nested puddings', t => { + const testOpts = puddin({ + a: {}, + b: {} + }) + const nestedOpts = puddin({}) // actual values declared should not matter + const arr = [] + const opts = testOpts({a: 1}).concat( + {b: 3}, + nestedOpts({}).concat(nestedOpts({b: 2})) + ) + for (let [key, value] of opts.entries()) { + arr.push([key, value]) + } + t.deepEqual(arr, [ + ['a', 1], + ['b', 2] + ], 'reaches into nested puddings even if they don\'t declare a key') + testOpt + t.done() +}) + +test('Symbol.iterator', t => { + const testOpts = puddin({ + a: {}, + b: {} + }) + const arr = [] + const opts = testOpts({a: 1, b: 2, c: 3}) + for (let [key, value] of opts) { + arr.push([key, value]) + } + t.deepEqual(arr, [ + ['a', 1], + ['b', 2] + ], 'pudding itself is an iterator') + t.done() +}) + +test('keys', t => { + const testOpts = puddin({ + a: {}, + b: {} + }) + const arr = [] + const opts = testOpts({a: 1, b: 2, c: 3}) + for (let key of opts.keys()) { + arr.push(key) + } + t.deepEqual(arr, [ + 'a', 'b' + ], '.keys() iterates over keys') + t.done() +}) + +test('values', t => { + const testOpts = puddin({ + a: {}, + b: {} + }) + const arr = [] + const opts = testOpts({a: 1, b: 2, c: 3}) + for (let key of opts.values()) { + arr.push(key) + } + t.deepEqual(arr, [ + 1, 2 + ], '.values() iterates over values') + t.done() +}) + +test('opts.other iteration', t => { + const testOpts = puddin({ + a: {} + }, { + other (key) { return /^special-/.test(key) } + }) + const arr = [] + const opts = testOpts({ + 'special-a': 3, + a: 1, + b: 2, + 'special-b': 4, + 'a-special': 5 + }) + for (let [key, value] of opts.entries()) { + arr.push([key, value]) + } + t.deepEqual(arr, [ + ['a', 1], + ['special-a', 3], + ['special-b', 4] + ], 'iterates over opts.other keys after primary keys') + t.done() +}) + +test('opts.other iteration over nested puddings', t => { + const testOpts = puddin({ + a: {} + }, { + other (key) { return /^special-/.test(key) } + }) + const nestedOpts = puddin({ + b: {} + }) + const arr = [] + const opts = testOpts({ + 'special-b': 4 + }).concat({a: 3}, nestedOpts({ + a: 1, + 'a-special': 5 + }).concat(nestedOpts({ + b: 2, + 'special-a': 3 + }))) + for (let [key, value] of opts.entries()) { + arr.push([key, value]) + } + t.deepEqual(arr, [ + ['a', 1], + ['special-a', 3], + ['special-b', 4] + ], 'expected order even with nested opts.others') + t.done() +})