diff --git a/src/Core__Object.res b/src/Core__Object.res index e2e14c50..c02eef1e 100644 --- a/src/Core__Object.res +++ b/src/Core__Object.res @@ -11,8 +11,35 @@ @variadic @val external assignMany: ({..}, array<{..}>) => {..} = "Object.assign" @val external copy: (@as(json`{}`) _, {..}) => {..} = "Object.assign" -@get_index external get: ({..}, string) => option<'a> = "" -@get_index external getSymbol: ({..}, Core__Symbol.t) => option<'a> = "" +/** +`get` gets the value of a property by name. Returns `None` if the property does not exist or has the value `undefined`. Otherwise returns `Some`, including if the value is `null`. + +## Examples + +```rescript +{"a": 1}->Object.get("a") // Some(1) +{"a": 1}->Object.get("b") // None +{"a": undefined}->Object.get("a") // None +{"a": null}->Object.get("a") // Some(null) +{"a": 1}->Object.get("toString")->Option.isSome // true +``` +*/ +@get_index +external get: ({..}, string) => option<'a> = "" +/** +`getSymbol` gets the value of a property by symbol. Returns `None` if the property does not exist or has the value `undefined`. Otherwise returns `Some`, including if the value is `null`. + +## Examples + +```rescript +let fruit = Symbol.make("fruit") +let x = Object.empty() +x->Object.setSymbol(fruit, "banana") +x->Object.getSymbol(fruit) // Some("banana") +``` +*/ +@get_index +external getSymbol: ({..}, Core__Symbol.t) => option<'a> = "" @get_index external getSymbolUnsafe: ({..}, Core__Symbol.t) => 'a = "" @set_index external set: ({..}, string, 'a) => unit = "" diff --git a/test/ObjectTests.mjs b/test/ObjectTests.mjs new file mode 100644 index 00000000..fe718d1b --- /dev/null +++ b/test/ObjectTests.mjs @@ -0,0 +1,148 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Test from "./Test.mjs"; +import * as Curry from "rescript/lib/es6/curry.js"; +import * as Caml_obj from "rescript/lib/es6/caml_obj.js"; +import * as Core__Option from "../src/Core__Option.mjs"; + +var eq = Caml_obj.equal; + +function runGetTest(i) { + Test.run([ + [ + "ObjectTests.res", + 15, + 22, + 46 + ], + "Object.get: " + i.title + "" + ], Curry._1(i.get, Curry._1(i.source, undefined)), eq, i.expected); +} + +runGetTest({ + title: "prop exists, return Some", + source: (function (param) { + return { + a: 1 + }; + }), + get: (function (__x) { + return __x["a"]; + }), + expected: 1 + }); + +runGetTest({ + title: "prop NOT exist, return None", + source: (function (param) { + return { + a: 1 + }; + }), + get: (function (i) { + return i["banana"]; + }), + expected: undefined + }); + +runGetTest({ + title: "prop like toString, return Some", + source: (function (param) { + return { + a: 1 + }; + }), + get: (function (i) { + return Core__Option.isSome(i["toString"]); + }), + expected: true + }); + +runGetTest({ + title: "prop exist but explicitly undefined, return None", + source: (function (param) { + return { + a: undefined + }; + }), + get: (function (i) { + return i["a"]; + }), + expected: undefined + }); + +runGetTest({ + title: "prop exist but explicitly null, return None", + source: (function (param) { + return { + a: null + }; + }), + get: (function (i) { + return i["a"]; + }), + expected: null + }); + +runGetTest({ + title: "prop exists and is an array, can get it", + source: (function (param) { + return { + a: [ + 1, + 2, + 3 + ] + }; + }), + get: (function (i) { + return Core__Option.getWithDefault(Core__Option.map(i["a"], (function (i) { + return i.concat([ + 4, + 5 + ]); + })), []); + }), + expected: [ + 1, + 2, + 3, + 4, + 5 + ] + }); + +function getSymbolTestWhenExists(param) { + var obj = {}; + var fruit = Symbol("fruit"); + obj[fruit] = "banana"; + var retrieved = obj[fruit]; + Test.run([ + [ + "ObjectTests.res", + 75, + 15, + 63 + ], + "Object.getSymbol when exists return it as Some" + ], retrieved, eq, "banana"); +} + +getSymbolTestWhenExists(undefined); + +Test.run([ + [ + "ObjectTests.res", + 84, + 13, + 65 + ], + "Object.getSymbol when not exists return it as None" + ], ({})[Symbol("fruit")], eq, undefined); + +export { + eq , + runGetTest , + getSymbolTestWhenExists , +} +/* Not a pure module */ diff --git a/test/ObjectTests.res b/test/ObjectTests.res new file mode 100644 index 00000000..27a99d7a --- /dev/null +++ b/test/ObjectTests.res @@ -0,0 +1,88 @@ +open RescriptCore + +let eq = (a, b) => a == b + +// ===== get ===== + +type getTestData<'obj, 'res, 'expected> = { + title: string, + source: unit => 'obj, + get: 'obj => 'res, + expected: 'expected, +} + +let runGetTest = i => + Test.run(__POS_OF__(`Object.get: ${i.title}`), i.source()->i.get, eq, i.expected) + +{ + title: "prop exists, return Some", + source: () => {"a": 1}, + get: Object.get(_, "a"), + expected: Some(1), +}->runGetTest + +{ + title: "prop NOT exist, return None", + source: () => {"a": 1}, + get: i => i->Object.get("banana"), + expected: None, +}->runGetTest + +{ + title: "prop like toString, return Some", + source: () => {"a": 1}, + get: i => i->Object.get("toString")->Option.isSome, + expected: true, +}->runGetTest + +{ + title: "prop exist but explicitly undefined, return None", + source: () => {"a": undefined}, + get: i => i->Object.get("a"), + expected: None, +}->runGetTest + +{ + title: "prop exist but explicitly null, return None", + source: () => {"a": null}, + get: i => i->Object.get("a"), + expected: Some(null), +}->runGetTest + +{ + title: "prop exists and is an array, can get it", + source: () => {"a": [1, 2, 3]}, + get: i => i->Object.get("a")->Option.map(i => i->Array.concat([4, 5]))->Option.getWithDefault([]), + expected: [1, 2, 3, 4, 5], +}->runGetTest + +// This throws an exception +// { +// title: "prop exists but casted wrong on get", +// source: () => {"a": 34}, +// get: i => i->Object.get("a")->Option.map(i => i->Array.concat([4, 5]))->Option.getWithDefault([]), +// expected: [], +// }->runGetTest + +// ===== getSymbol ===== + +let getSymbolTestWhenExists = () => { + let obj = Object.empty() + let fruit = Symbol.make("fruit") + obj->Object.setSymbol(fruit, "banana") + let retrieved = obj->Object.getSymbol(fruit) + Test.run( + __POS_OF__(`Object.getSymbol when exists return it as Some`), + retrieved, + eq, + Some("banana"), + ) +} +getSymbolTestWhenExists() + +Test.run( + __POS_OF__(`Object.getSymbol when not exists return it as None`), + Object.empty()->Object.getSymbol(Symbol.make("fruit")), + eq, + None, +) diff --git a/test/TestSuite.mjs b/test/TestSuite.mjs index c968bd8f..80ecf948 100644 --- a/test/TestSuite.mjs +++ b/test/TestSuite.mjs @@ -4,6 +4,7 @@ import * as IntTests from "./IntTests.mjs"; import * as TestTests from "./TestTests.mjs"; import * as ArrayTests from "./ArrayTests.mjs"; import * as ErrorTests from "./ErrorTests.mjs"; +import * as ObjectTests from "./ObjectTests.mjs"; import * as PromiseTest from "./PromiseTest.mjs"; var bign = TestTests.bign; @@ -26,10 +27,14 @@ var Concurrently = PromiseTest.Concurrently; var panicTest = ErrorTests.panicTest; -var eq = IntTests.eq; - var $$catch = IntTests.$$catch; +var eq = ObjectTests.eq; + +var runGetTest = ObjectTests.runGetTest; + +var getSymbolTestWhenExists = ObjectTests.getSymbolTestWhenExists; + export { bign , TestError , @@ -41,7 +46,9 @@ export { Catching , Concurrently , panicTest , - eq , $$catch , + eq , + runGetTest , + getSymbolTestWhenExists , } /* IntTests Not a pure module */ diff --git a/test/TestSuite.res b/test/TestSuite.res index 6277bf57..ca2a63ca 100644 --- a/test/TestSuite.res +++ b/test/TestSuite.res @@ -3,3 +3,4 @@ include PromiseTest include ErrorTests include ArrayTests include IntTests +include ObjectTests