{"_id":"@iadvize-oss/opaque-union","_rev":"305-ed507bd799ca771dc6d96998f1c97bf4","name":"@iadvize-oss/opaque-union","dist-tags":{"NO-TICKET-first-beta":"0.0.0-canary-503ebf9-1592730802608","NO-TICKET-add-codeowners":"0.0.1-beta.0-canary-41ad66e-1592731368163","NO-TICKET-fix-jest-config-typings":"0.0.1-beta.0-canary-e841429-1593027895970","NO-TICKET-fix-codeowners":"0.0.1-beta.0-canary-ee026d8-1593028051773","dependabot/npm_and_yarn/lodash-4.17.19":"0.0.1-beta.0-canary-e4626ea-1595309115749","dependabot/npm_and_yarn/highlight.js-10.4.0":"0.0.1-beta.0-canary-e5e6a73-1606260801933","dependabot/npm_and_yarn/dot-prop-4.2.1":"0.0.1-beta.0-canary-8570e70-1606292401028","NO-TICKET-opaque-variation":"0.0.1-beta.0-canary-9cd51e3-1606731377063","NO-TICKET-v1-release":"0.0.1-beta.1-canary-2783bc8-1606732279589","dependabot/npm_and_yarn/highlight.js-10.4.1":"1.0.0-canary-1c65345-1607115545094","dependabot/npm_and_yarn/ini-1.3.8":"1.0.0-canary-fa8d5e2-1607812234888","dependabot/npm_and_yarn/node-notifier-8.0.1":"1.0.0-canary-07fca8a-1608660098520","dependabot/npm_and_yarn/y18n-4.0.1":"1.0.0-canary-25d80d2-1617264623120","dependabot-add-v2-config-file":"1.0.0-canary-b9a82a0-1619732791781","dependabot/npm_and_yarn/handlebars-4.7.7":"1.0.0-canary-cfb0616-1622558091338","dependabot/npm_and_yarn/rollup-2.50.5":"1.0.0-canary-cfb0616-1622558101081","dependabot/npm_and_yarn/lodash-4.17.21":"1.0.0-canary-22d3af7-1622558474645","dependabot/npm_and_yarn/hosted-git-info-2.8.9":"1.0.0-canary-04903b0-1622558756695","dependabot/npm_and_yarn/ws-7.4.6":"1.0.0-canary-2c5d75e-1622559635057","dependabot/npm_and_yarn/tsd-0.16.0":"1.0.0-canary-2741463-1622560304938","NO-TICKET-UpdateDeps":"1.0.0-canary-de4c831-1622560624810","latest":"1.0.1","dependabot/npm_and_yarn/typedoc-0.20.36":"1.0.1-canary-82aa02d-1622622027987","dependabot/npm_and_yarn/iadvize-oss/eslint-config-2.2.0":"1.0.1-canary-a13c986-1622626732673","dependabot/npm_and_yarn/ts-jest-26.5.6":"1.0.1-canary-c299010-1622685695358","dependabot/npm_and_yarn/rollup-plugin-typescript2-0.30.0":"1.0.1-canary-c89b970-1622710260498","dependabot/npm_and_yarn/rollup/plugin-commonjs-19.0.0":"1.0.1-canary-492609d-1622711125483","dependabot/npm_and_yarn/tslib-2.2.0":"1.0.1-canary-492609d-1622711126166","dependabot/npm_and_yarn/monocle-ts-2.3.10":"1.0.1-canary-492609d-1622711128865","dependabot/npm_and_yarn/types/jest-26.0.23":"1.0.1-canary-37f0dc6-1622772106711","dependabot/npm_and_yarn/rollup-2.50.6":"1.0.1-canary-37f0dc6-1622772118990","dependabot/npm_and_yarn/typescript-4.3.2":"1.0.1-canary-37f0dc6-1622772136217","dependabot/npm_and_yarn/eslint-7.27.0":"1.0.1-canary-37f0dc6-1622772157545","dependabot/npm_and_yarn/rollup-2.51.0":"1.0.1-canary-799abd2-1623031301194","dependabot/npm_and_yarn/eslint-7.28.0":"1.0.1-canary-799abd2-1623031322256","dependabot/npm_and_yarn/jest-27.0.4":"1.0.1-canary-6890547-1623055506199","dependabot/npm_and_yarn/rollup-2.51.1":"1.0.1-canary-6890547-1623204100365","dependabot/npm_and_yarn/rollup-2.51.2":"1.0.1-canary-bb18c0b-1623636094178","dependabot/npm_and_yarn/tslib-2.3.0":"1.0.1-canary-bb18c0b-1623636116080","dependabot/npm_and_yarn/rollup-2.52.0":"1.0.1-canary-a96e62a-1623895320134","dependabot/npm_and_yarn/typescript-4.3.3":"1.0.1-canary-a96e62a-1623895331260","dependabot/npm_and_yarn/typedoc-0.20.37":"1.0.1-canary-a96e62a-1623895353105","dependabot/npm_and_yarn/typescript-4.3.4":"1.0.1-canary-4b6b557-1623981696441","dependabot/npm_and_yarn/rollup-2.52.1":"1.0.1-canary-4b6b557-1623981706276","dependabot/npm_and_yarn/typedoc-0.21.0":"1.0.1-canary-4660650-1624240879986","dependabot/npm_and_yarn/eslint-7.29.0":"1.0.1-canary-4660650-1624240894473","dependabot/npm_and_yarn/rollup-2.52.2":"1.0.1-canary-c2c1dd0-1624327276179","dependabot/npm_and_yarn/jest-27.0.5":"1.0.1-canary-6148f5e-1624413704884","dependabot/npm_and_yarn/typedoc-0.21.2":"1.0.1-canary-6148f5e-1624845686121","dependabot/npm_and_yarn/rollup-2.52.3":"1.0.1-canary-6148f5e-1624845697597","dependabot/npm_and_yarn/typescript-4.3.5":"1.0.1-canary-3c24b8c-1625104915737","dependabot/npm_and_yarn/rollup-2.52.4":"1.0.1-canary-3c24b8c-1625104931950","dependabot/npm_and_yarn/rollup-2.52.6":"1.0.1-canary-8ac59cc-1625191292560","dependabot/npm_and_yarn/eslint-7.30.0":"1.0.1-canary-3a35ae8-1625450487402","dependabot/npm_and_yarn/types/jest-26.0.24":"1.0.1-canary-316b40c-1625623277944","dependabot/npm_and_yarn/jest-27.0.6":"1.0.1-canary-9a5082e-1625642848254","dependabot/npm_and_yarn/rollup-2.52.8":"1.0.1-canary-9a5082e-1625709708360","dependabot/npm_and_yarn/typedoc-0.21.4":"1.0.1-canary-1a2439b-1626055312419","dependabot/npm_and_yarn/rollup/plugin-commonjs-19.0.1":"1.0.1-canary-d8a03f2-1626400898820","dependabot/npm_and_yarn/rollup-2.53.2":"1.0.1-canary-d8a03f2-1626400909081","dependabot/npm_and_yarn/eslint-7.31.0":"1.0.1-canary-2fb4fd2-1626660476713","dependabot/npm_and_yarn/rollup-2.53.3":"1.0.1-canary-d3ea5cf-1626919299486","dependabot/npm_and_yarn/rollup-2.54.0":"1.0.1-canary-a8c0b11-1627264897950","dependabot/npm_and_yarn/rollup/plugin-commonjs-19.0.2":"1.0.1-canary-1ea1131-1627351299847","dependabot/npm_and_yarn/rollup-2.55.0":"1.0.1-canary-6e7a4cb-1627524096338","dependabot/npm_and_yarn/rollup-2.55.1":"1.0.1-canary-2c88a36-1627610493388","dependabot/npm_and_yarn/rollup/plugin-commonjs-20.0.0":"1.0.1-canary-f07d762-1627869696548","dependabot/npm_and_yarn/eslint-7.32.0":"1.0.1-canary-f07d762-1627869711930","dependabot/npm_and_yarn/typedoc-0.21.5":"1.0.1-canary-f07d762-1627869720614","dependabot/npm_and_yarn/rollup-2.56.0":"1.0.1-canary-f07d762-1628215314944","dependabot/npm_and_yarn/rollup-2.56.1":"1.0.1-canary-f07d762-1628474496337","dependabot/npm_and_yarn/rollup-2.56.2":"1.0.1-canary-f07d762-1628647347029","dependabot/npm_and_yarn/types/jest-27.0.0":"1.0.1-canary-f07d762-1628647387318","dependabot/npm_and_yarn/types/jest-27.0.1":"1.0.1-canary-f07d762-1628820112878","dependabot/npm_and_yarn/typedoc-0.21.6":"1.0.1-canary-f07d762-1629424898426","dependabot/npm_and_yarn/rollup-2.56.3":"1.0.1-canary-f07d762-1629770518609","dependabot/npm_and_yarn/typedoc-0.21.9":"1.0.1-canary-f07d762-1630288984407","dependabot/npm_and_yarn/typedoc-0.22.3":"1.0.1-canary-f07d762-1631498614639","dependabot/npm_and_yarn/typedoc-0.22.4":"1.0.1-canary-f07d762-1632103286904","dependabot/npm_and_yarn/types/jest-27.0.2":"1.0.1-canary-f07d762-1632276096910","dependabot/npm_and_yarn/rollup-2.57.0":"1.0.1-canary-f07d762-1632362499686","dependabot/npm_and_yarn/typedoc-0.22.5":"1.0.1-canary-f07d762-1633313001120","dependabot/npm_and_yarn/rollup-2.58.0":"1.0.1-canary-f07d762-1633313028711","dependabot/npm_and_yarn/rollup/plugin-commonjs-21.0.0":"1.0.1-canary-f07d762-1633313119645","dependabot/npm_and_yarn/eslint-8.0.0":"1.0.1-canary-f07d762-1633917878497","dependabot/npm_and_yarn/eslint-8.0.1":"1.0.1-canary-f07d762-1634263346049","dependabot/npm_and_yarn/typedoc-0.22.6":"1.0.1-canary-f07d762-1634522556199","dependabot/npm_and_yarn/rollup/plugin-commonjs-21.0.1":"1.0.1-canary-f07d762-1634695308650","dependabot/npm_and_yarn/eslint-8.1.0":"1.0.1-canary-f07d762-1635127386846","dependabot/npm_and_yarn/typedoc-0.22.7":"1.0.1-canary-f07d762-1635127408266","dependabot/npm_and_yarn/rollup-2.58.3":"1.0.1-canary-f07d762-1635213770198","dependabot/npm_and_yarn/rollup-2.59.0":"1.0.1-canary-f07d762-1635818504628","dependabot/npm_and_yarn/typedoc-0.22.8":"1.0.1-canary-f07d762-1636337068092","dependabot/npm_and_yarn/eslint-8.2.0":"1.0.1-canary-f07d762-1636337092870","dependabot/npm_and_yarn/rollup-2.60.0":"1.0.1-canary-f07d762-1636941720315","dependabot/npm_and_yarn/typedoc-0.22.9":"1.0.1-canary-f07d762-1636941823473","dependabot/npm_and_yarn/types/jest-27.0.3":"1.0.1-canary-f07d762-1637287404307","dependabot/npm_and_yarn/eslint-8.3.0":"1.0.1-canary-f07d762-1637546660946","dependabot/npm_and_yarn/rollup-2.60.1":"1.0.1-canary-f07d762-1637632921253","dependabot/npm_and_yarn/typedoc-0.22.10":"1.0.1-canary-f07d762-1637805733845","dependabot/npm_and_yarn/rollup-2.60.2":"1.0.1-canary-f07d762-1638324127149","dependabot/npm_and_yarn/eslint-8.4.0":"1.0.1-canary-f07d762-1638756223599","dependabot/npm_and_yarn/eslint-8.4.1":"1.0.1-canary-f07d762-1638842580192","dependabot/npm_and_yarn/rollup-2.61.0":"1.0.1-canary-f07d762-1639101765011","dependabot/npm_and_yarn/rollup-2.61.1":"1.0.1-canary-f07d762-1639361013854","dependabot/npm_and_yarn/eslint-8.5.0":"1.0.1-canary-f07d762-1639965834905","dependabot/npm_and_yarn/rollup-2.62.0":"1.0.1-canary-f07d762-1640570599778","dependabot/npm_and_yarn/types/jest-27.4.0":"1.0.1-canary-f07d762-1640916188050","dependabot/npm_and_yarn/eslint-8.6.0":"1.0.1-canary-f07d762-1641175490579","dependabot/npm_and_yarn/rollup-2.63.0":"1.0.1-canary-f07d762-1641348124460","dependabot/npm_and_yarn/rollup-2.64.0":"1.0.1-canary-f07d762-1642385059185","dependabot/npm_and_yarn/eslint-8.7.0":"1.0.1-canary-f07d762-1642385085432","dependabot/npm_and_yarn/typedoc-0.22.11":"1.0.1-canary-f07d762-1642557710679","dependabot/npm_and_yarn/rollup-2.66.0":"1.0.1-canary-f07d762-1642989708617","dependabot/npm_and_yarn/rollup-2.66.1":"1.0.1-canary-f07d762-1643162527885","dependabot/npm_and_yarn/eslint-8.8.0":"1.0.1-canary-f07d762-1643594633123","dependabot/npm_and_yarn/rollup-2.67.0":"1.0.1-canary-f07d762-1643853809186","dependabot/npm_and_yarn/rollup-2.67.1":"1.0.1-canary-f07d762-1644285846227","dependabot/npm_and_yarn/rollup-2.67.2":"1.0.1-canary-f07d762-1644545319066","dependabot/npm_and_yarn/eslint-8.9.0":"1.0.1-canary-f07d762-1644804191958","dependabot/npm_and_yarn/rollup-2.67.3":"1.0.1-canary-f07d762-1645408911424","dependabot/npm_and_yarn/typedoc-0.22.12":"1.0.1-canary-f07d762-1645409051123","dependabot/npm_and_yarn/rollup-2.68.0":"1.0.1-canary-f07d762-1645581802668","dependabot/npm_and_yarn/types/jest-27.4.1":"1.0.1-canary-f07d762-1645668201733","dependabot/npm_and_yarn/rollup/plugin-commonjs-21.0.2":"1.0.1-canary-f07d762-1645668210427","dependabot/npm_and_yarn/eslint-8.10.0":"1.0.1-canary-f07d762-1646013853556","dependabot/npm_and_yarn/rollup-2.69.0":"1.0.1-canary-f07d762-1646272950919","dependabot/npm_and_yarn/rollup-2.69.2":"1.0.1-canary-f07d762-1646618581203","dependabot/npm_and_yarn/typedoc-0.22.13":"1.0.1-canary-f07d762-1646618591074","dependabot/npm_and_yarn/rollup-2.70.0":"1.0.1-canary-f07d762-1646704957908","dependabot/npm_and_yarn/eslint-8.11.0":"1.0.1-canary-f07d762-1647223402354","dependabot/npm_and_yarn/rollup-2.70.1":"1.0.1-canary-f07d762-1647309860824","dependabot/npm_and_yarn/minimist-1.2.6":"1.0.1-canary-f07d762-1648335406187","dependabot/npm_and_yarn/eslint-8.12.0":"1.0.1-canary-f07d762-1648432949467","dependabot/npm_and_yarn/rollup/plugin-commonjs-21.0.3":"1.0.1-canary-f07d762-1648433038403","dependabot/npm_and_yarn/typedoc-0.22.14":"1.0.1-canary-f07d762-1649383413667","dependabot/npm_and_yarn/typedoc-0.22.15":"1.0.1-canary-f07d762-1649642533205","dependabot/npm_and_yarn/eslint-8.13.0":"1.0.1-canary-f07d762-1649642643089","dependabot/npm_and_yarn/rollup/plugin-commonjs-21.1.0":"1.0.1-canary-f07d762-1650247441447","dependabot/npm_and_yarn/rollup-2.70.2":"1.0.1-canary-f07d762-1650247487211","dependabot/npm_and_yarn/eslint-8.14.0":"1.0.1-canary-f07d762-1650855285310","dependabot/npm_and_yarn/rollup-2.71.1":"1.0.1-canary-f07d762-1651457039507","dependabot/npm_and_yarn/types/jest-27.5.0":"1.0.1-canary-f07d762-1651543362807","dependabot/npm_and_yarn/rollup-2.72.0":"1.0.1-canary-f07d762-1651802517935","dependabot/npm_and_yarn/rollup-2.72.1":"1.0.1-canary-f07d762-1652063188729","dependabot/npm_and_yarn/eslint-8.15.0":"1.0.1-canary-f07d762-1652063174415","dependabot/npm_and_yarn/rollup-2.73.0":"1.0.1-canary-f07d762-1652666579732","dependabot/npm_and_yarn/rollup-2.74.1":"1.0.1-canary-f07d762-1653012197332","dependabot/npm_and_yarn/eslint-8.16.0":"1.0.1-canary-f07d762-1653271344220","dependabot/npm_and_yarn/rollup-2.75.3":"1.0.1-canary-f07d762-1653876120437","dependabot/npm_and_yarn/typedoc-0.22.16":"1.0.1-canary-f07d762-1653962587438","dependabot/npm_and_yarn/rollup-2.75.4":"1.0.1-canary-f07d762-1654049397500","dependabot/npm_and_yarn/rollup-2.75.5":"1.0.1-canary-f07d762-1654135408243","dependabot/npm_and_yarn/typedoc-0.22.17":"1.0.1-canary-f07d762-1654135427904","dependabot/npm_and_yarn/eslint-8.17.0":"1.0.1-canary-f07d762-1654481051315","dependabot/npm_and_yarn/rollup-2.75.6":"1.0.1-canary-f07d762-1654653730041","dependabot/npm_and_yarn/eslint-8.18.0":"1.0.1-canary-f07d762-1655690661708","dependabot/npm_and_yarn/rollup-2.75.7":"1.0.1-canary-f07d762-1655777284220","dependabot/npm_and_yarn/jsdom-16.7.0":"1.0.1-canary-f07d762-1656064386298","dependabot/npm_and_yarn/rollup/plugin-commonjs-22.0.1":"1.0.1-canary-f07d762-1656296141566","dependabot/npm_and_yarn/typedoc-0.23.1":"1.0.1-canary-f07d762-1656296250510","dependabot/npm_and_yarn/typedoc-0.23.2":"1.0.1-canary-f07d762-1656381846589","dependabot/npm_and_yarn/typedoc-0.23.5":"1.0.1-canary-f07d762-1656900179721","dependabot/npm_and_yarn/eslint-8.19.0":"1.0.1-canary-f07d762-1656900277399","dependabot/npm_and_yarn/typedoc-0.23.6":"1.0.1-canary-f07d762-1657245815754","dependabot/npm_and_yarn/rollup-2.76.0":"1.0.1-canary-f07d762-1657505351465","dependabot/npm_and_yarn/typedoc-0.23.7":"1.0.1-canary-f07d762-1657505493262","dependabot/npm_and_yarn/typedoc-0.23.8":"1.0.1-canary-f07d762-1658109887094","dependabot/npm_and_yarn/eslint-8.20.0":"1.0.1-canary-f07d762-1658109901212","dependabot/npm_and_yarn/rollup-2.77.0":"1.0.1-canary-f07d762-1658109934928","dependabot/npm_and_yarn/terser-5.14.2":"1.0.1-canary-f07d762-1658281516370","dependabot/npm_and_yarn/typedoc-0.23.9":"1.0.1-canary-f07d762-1658714680437","dependabot/npm_and_yarn/rollup-2.77.1":"1.0.1-canary-f07d762-1658887361101","dependabot/npm_and_yarn/rollup-2.77.2":"1.0.1-canary-f07d762-1658973717872","dependabot/npm_and_yarn/typedoc-0.23.10":"1.0.1-canary-f07d762-1659319954596","dependabot/npm_and_yarn/eslint-8.21.0":"1.0.1-canary-f07d762-1659405782966","dependabot/npm_and_yarn/rollup/plugin-commonjs-22.0.2":"1.0.1-canary-f07d762-1659924257781","dependabot/npm_and_yarn/rollup-2.77.3":"1.0.1-canary-f07d762-1660269737621","dependabot/npm_and_yarn/eslint-8.22.0":"1.0.1-canary-f07d762-1660529100798","dependabot/npm_and_yarn/rollup-2.78.0":"1.0.1-canary-f07d762-1660529139621","dependabot/npm_and_yarn/rollup-2.78.1":"1.0.1-canary-f07d762-1661133896211","dependabot/npm_and_yarn/eslint-8.23.0":"1.0.1-canary-f07d762-1661738862203","dependabot/npm_and_yarn/typedoc-0.23.11":"1.0.1-canary-f07d762-1661738960872","dependabot/npm_and_yarn/typedoc-0.23.13":"1.0.1-canary-f07d762-1661997888490","dependabot/npm_and_yarn/rollup-2.79.0":"1.0.1-canary-f07d762-1661997907021","dependabot/npm_and_yarn/typedoc-0.23.14":"1.0.1-canary-f07d762-1662382366553","dependabot/npm_and_yarn/eslint-8.23.1":"1.0.1-canary-f07d762-1663034663852","dependabot/npm_and_yarn/typedoc-0.23.15":"1.0.1-canary-f07d762-1663553270612","dependabot/npm_and_yarn/rollup-2.79.1":"1.0.1-canary-f07d762-1663898620510","dependabot/npm_and_yarn/eslint-8.24.0":"1.0.1-canary-f07d762-1664157959216","dependabot/npm_and_yarn/eslint-8.25.0":"1.0.1-canary-f07d762-1665367698034","dependabot/npm_and_yarn/rollup/plugin-commonjs-23.0.0":"1.0.1-canary-f07d762-1665367877607","dependabot/npm_and_yarn/typedoc-0.23.16":"1.0.1-canary-f07d762-1665453779558","dependabot/npm_and_yarn/typedoc-0.23.17":"1.0.1-canary-f07d762-1666144978962","dependabot/npm_and_yarn/rollup/plugin-commonjs-23.0.1":"1.0.1-canary-f07d762-1666317907483","dependabot/npm_and_yarn/typedoc-0.23.18":"1.0.1-canary-f07d762-1666576903167","dependabot/npm_and_yarn/eslint-8.26.0":"1.0.1-canary-f07d762-1666577031364","dependabot/npm_and_yarn/rollup/plugin-commonjs-23.0.2":"1.0.1-canary-f07d762-1666577075239","dependabot/npm_and_yarn/typedoc-0.23.19":"1.0.1-canary-f07d762-1667181742373","dependabot/npm_and_yarn/eslint-8.27.0":"1.0.1-canary-f07d762-1667786536916","dependabot/npm_and_yarn/typedoc-0.23.20":"1.0.1-canary-f07d762-1667786647779","dependabot/npm_and_yarn/typedoc-0.23.21":"1.0.1-canary-f07d762-1668391468215","dependabot/npm_and_yarn/eslint-8.28.0":"1.0.1-canary-f07d762-1668996225529","dependabot/npm_and_yarn/rollup/plugin-commonjs-23.0.3":"1.0.1-canary-f07d762-1669601139738","dependabot/npm_and_yarn/eslint-8.29.0":"1.0.1-canary-f07d762-1670205972153","dependabot/npm_and_yarn/decode-uri-component-0.2.2":"1.0.1-canary-f07d762-1670319096136","dependabot/npm_and_yarn/rollup/plugin-commonjs-23.0.4":"1.0.1-canary-f07d762-1670464891557","dependabot/npm_and_yarn/qs-6.5.3":"1.0.1-canary-f07d762-1670755820150","dependabot/npm_and_yarn/typedoc-0.23.22":"1.0.1-canary-f07d762-1670810566504","dependabot/npm_and_yarn/rollup/plugin-commonjs-23.0.5":"1.0.1-canary-f07d762-1671156059279","dependabot/npm_and_yarn/typedoc-0.23.23":"1.0.1-canary-f07d762-1671415306995","dependabot/npm_and_yarn/eslint-8.30.0":"1.0.1-canary-f07d762-1671415353243","dependabot/npm_and_yarn/rollup/plugin-commonjs-24.0.0":"1.0.1-canary-f07d762-1671415397506","dependabot/npm_and_yarn/json5-and-tsconfig-paths-2.2.3":"1.0.1-canary-f07d762-1672606645423","dependabot/npm_and_yarn/eslint-8.31.0":"1.0.1-canary-f07d762-1672624951306","dependabot/npm_and_yarn/json5-1.0.2":"1.0.1-canary-f07d762-1673119159310","dependabot/npm_and_yarn/typedoc-0.23.24":"1.0.1-canary-f07d762-1673229859074","dependabot/npm_and_yarn/eslint-8.32.0":"1.0.1-canary-f07d762-1673836041330","dependabot/npm_and_yarn/rollup/plugin-commonjs-24.0.1":"1.0.1-canary-f07d762-1674441891652","dependabot/npm_and_yarn/eslint-8.33.0":"1.0.1-canary-f07d762-1675044780414","dependabot/npm_and_yarn/eslint-8.34.0":"1.0.1-canary-f07d762-1676258231170","dependabot/npm_and_yarn/typedoc-0.23.25":"1.0.1-canary-f07d762-1676258327053","dependabot/npm_and_yarn/eslint-8.35.0":"1.0.1-canary-f07d762-1677467426904","dependabot/npm_and_yarn/typedoc-0.23.26":"1.0.1-canary-f07d762-1677467447747","dependabot/npm_and_yarn/minimist-1.2.8":"1.0.1-canary-f07d762-1677979873279"},"versions":{"0.0.0-canary-503ebf9-1592730802608":{"name":"@iadvize-oss/opaque-union","version":"0.0.0-canary-503ebf9-1592730802608","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.0-canary-503ebf9-1592730802608","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"dc6c91b87d615286b5bd45e1a094d94f90126e91","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.0-canary-503ebf9-1592730802608.tgz","fileCount":8,"integrity":"sha512-oRLKnf3YB/hqcgj5b7HKvTfqiLOyfswGSu4rcecGw8NXZwwJMtctozkP18IAOZnRINjwyFDn7vVsBeldD9UIHA==","signatures":[{"sig":"MEQCIAIL1cNkkPjDyctXAD6t1mFVwue/tEykPXdVsUfN+X8JAiAMrrJz+ooPjU8bvShrHdpK/GoP6Yq1SX0Tb0XvwpKRCA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":38879,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe7yTnCRA9TVsSAnZWagAAIkEP/1Rc5zvsDyN6rFpnEFiD\ntOniEcGrxjq4mQsF4dbfUV9pcsHfwZgTCd/IjFEna54SKsKJz3MQU/gyyYkh\nYvgMwZKgDGeIJfBMC8ObEgNy8Ykb5B6VC6oceUtjmuhK3u/EgJaKzJvrKyRn\nLBKfKtKfcm01s9HgaS8dL7GzyWN54geCFzIAfAPA4aGaiFJtouEIBkVwWlPJ\nNpoF9EY260iL53nI37Zvchhi3Vd2YeYQa3/mlSbUXwGLD1eUjT2r6TUmP9sH\ncsS5+ebCsK+E56jTo/XGB6+FZbD3rmRMsLPyOFMYNtioBik1nxX6r0bpbzlG\ne3r+6R6z1diSMdEjrQ9+V/WFQplrpuYB8lUW/uofDxMsfEYOwa5BskA8RJ9B\nDR56qdmoYEfbEPtndSaggDCPY/+2UQuO8vkf+jIV1jQeNVafnZiHBBW2o/nl\nd671TawY4Px7XWk4ZljNmrYxEmECSeycweXBNPv3MWb5z5o2lTst38RmSKKJ\nld8Djtoskn3iYJzopWW9+QTzNVAcfuVvIgp053V5yKYYT0GMoAaO7Q9t08hI\n1YwRjJLxvWPLWJuJ+W6jmMDsfT3J2usWRmE4TKpJ8Uj7i6bzAPCUcgFwm2go\nXf2UAvE/BSLid3ocZYOvG7STdZJV7xafUUhU8C4lRD0HfOyjZY8qDiGyLn+z\nVgGN\r\n=/LiV\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","gitHead":"0bab86268d17b3d95c9916b69a85b62ae594549e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.0-canary-503ebf9-1592730802608_1592730855126_0.988236053809431","host":"s3://npm-registry-packages"}},"0.0.1-beta.0":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"4b3eaddcf28dab764a1fafc99f231129f5304bb5","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0.tgz","fileCount":8,"integrity":"sha512-KAWCRJJz+fHD9ab5a/iheQg8t0TWl/fGUUfM/in9B5LgNvArh8CByLx5kbEpTn4U4sLq8KFLu0DAeJxCajyWmQ==","signatures":[{"sig":"MEYCIQC/381B6AFoVtulA8awJHONH4HdoUspjZJzEnPU1Ks0wgIhAIkf5KoQBzGKMORyEA4NEGcnVFLE/vCkIMimoBi8Z1fY","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":38857,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe7yaACRA9TVsSAnZWagAAONAP/30ec8SQMUr7PRkRLnl5\nWTZ0GwjnZAlGx0GkdyPbUUiKZuITelGL9zlSFBsVSGAec1wu++rKSkEACADo\nIjltzdmuLDd7SPVDpfm79+orQU2PDCXp+52uhOHiLL4GXGtB0VbKY2Ed3ozO\nZX+Zh+wOgCSszJq+FOJPu9/lcpMJ6EE0rnH/ygJCihF5apH3rIELlau26CK5\nuMauPNfso9UVPfpd/XWm8Xwcuom4sSN7pCIysDtcwSTuTr0BEmRcoxal1/5Q\ntjjrnGJeHXffjUBLGEbgRyUfSgPcHZZUnljUC2dK5Y68QiWH1XqBPvNcEuYB\nZioiDdeZAIJLeCmkbgiiYH/ps8ZMcvylXk+UbVQ/A/7qTxZUuzHyhS1yERDm\niRJahPq0e6OlMcuOAoh2AfkRkH0Ric/Jq6hSP0zbGgD2kWvX4zTJmcoK0ELg\nsVWdBnGocH9tG8SaO6BBbnmlLfqDZFx1RAyT30H2SU7+wfqJ7+lyjAksqHnw\nMfes1oouEnYn9qJROQcat4OI6IuvEhTPqxJzfnvw27oLwsrYE8OrA3V7tDuX\nwis2aM5JY3XS6bxmhLl+lQcDIVYMl+Rj0XXbnz1IosHg/qg8as/VhPGvia3J\nUBZabQONaNhtoD2Y6wn7OQtnI02z9SKUiRxITZvyO9nrxpjWL3qlBmpvx4uM\nrzdd\r\n=4wB8\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","gitHead":"014364f965c237e646721a494514b611aa3eee49","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0_1592731264467_0.7902143286567793","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-41ad66e-1592731368163":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-41ad66e-1592731368163","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-41ad66e-1592731368163","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"9547e1e8d4ced12c0d16805b3402df552d55bc33","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-41ad66e-1592731368163.tgz","fileCount":8,"integrity":"sha512-Sf6IW8QM/8QP+pbJ7k+cSGlw0dCenfpXXFAF0g81D2EDsuqHCNO7B8715/pPMzUrSG0hyHJSfJBieLtGskTOrA==","signatures":[{"sig":"MEUCIB25xmIh3G3RdcpkXBElqMpxfUIYoQr8bP8zPGToLY04AiEAgoHPm6+e0rGSzOaNG5gLZihXjkj9RL6yZ57kRxI6dd4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":3056,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe7ycpCRA9TVsSAnZWagAAa3AP/0d2QefgpFwzDm5XKC0D\n1FYEGNlaHpJlyKBCYMDnsH6VAE6koVsR5R8zXW1tjRh5R1flLtmssGruzFtD\nAvwNo3Z/Uh+y1VqGihciZoArhcP7xS3c6qEgjmXGLBwPItLuq0FqmkwX8esF\nx+m5Sn15PY8zMFa99b2r4Yfuylp5DTn+NVVpRnd9XXg4462JOXXWyziIei2D\nzM6gpOKEXIXnl1/T6xU1CwswCztY0/2DYWTcBPFgUNwutVME+mXuxa6+AWi+\nZE62z7nJEd9rJLNPfXgORqtHDF+crz1LmP0TKZBdR2n4ImcV5dYu1bTSE9s3\n973KQPug9tWuWsthfZdfi9AMdlDvS0e2uEgWnqk6BVSwPvDrdO1jGbaNoyBu\nHg1afdvoxpG13+nTjpjJDL0jxgRLyBhJ7Bmqh4Wu4gwzahM2Q7xR2BGYeddM\nCE3pDEXURcpRYAySRu+8eQjiz+ic09jQCmL4CDiYdvgUCQfPIpqCse79wG+W\nrP6KttI2p0I2haUsiEnyp2XqngwRaxjKmHX7dzDMsTuZ/KjF50MEkMOC3Kh5\nDAsb8g45Zz2FpQsOyymXEZxWfN50lHL6vm++s3NaNT9T4zy068GfFwka4xmL\nJ5tqME15juDJ2r9QlgmyNtWESZQQmXWGn1Bs/+yN4bSxTKd8qPLyNTut+3Zw\nEVdw\r\n=npr1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"ERROR: No README data found!","gitHead":"0991804bf25a8ccac7c535aea0ff0e85ef110452","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-41ad66e-1592731368163_1592731433290_0.740119604538219","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-995808e-1593027755533":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-995808e-1593027755533","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-995808e-1593027755533","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"59a1b987bd840b8ddadaf63484a7cd7422207a73","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-995808e-1593027755533.tgz","fileCount":8,"integrity":"sha512-99lbsnYh4h/drC218WjeEuvgcf/p4JSKUQTZpJ9vg527qITyVSkJvdL30+pKfqkjbv2xZ7NXNKYOCMK8iNDNNQ==","signatures":[{"sig":"MEQCIANSEJP2E2eMQTdj9CpG8B0VXN2sXO6+tkJBW51Uj2fOAiBks2nk5xE4qIubYl+47h1g0/B6jHbtEwN+IoohQse5xw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":39811,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe86zjCRA9TVsSAnZWagAAmuUP/3dHVh+4wo9v3qgdlxX0\nVb9139DOWg9M7gNmWw1ApiuyNsGMZtIAhw5aHV3NzF2hZh8bGpFgulilIY4b\nfcRmkE/OI3iXHHYeCo1dT5dUuCuRP8P7dIBjRUtfRKdfI20UTR9FEscb+Vzq\netavZRxXyPEA71sePpSn9aSLoZ9TVxxS6AAf0j3JDP5f2J3j+Whx75NoBR8u\nIfJMgnAbLeIZbIxHJr9/IXM++x6K/reo90pZvEwEvKbyhqWxaTlFtBGrPepd\nzcw3C27PdtX2UOLlbBN8Y4c5ZvriojCXmJT7HqcfhgNgAeetnCmlVuMFiDeY\nSUTcwKo5Hs3F3VsM8cxUNW2CogSuIZRHB2daQcrNdmSBEYr4HcxGAIK0xB44\npmlCs9nY1YdW+aEuTpO9CaiXyb9Nxgse4uyju5036LJdlcE02DHOTpIXMb0/\n67O/RuytDLVH9EIZbdJDHXmFxBYXjNKEiLTllhmmhqaRnGfT1xgy1y4A5lDQ\nL6PwqvKqhMBQzfLEF937AdFR+RIwbz7fq6ASerPasHHCTjxO0i/nZ5A1CIhz\nd6Wpfi5/qmA1yugx+t9GJCKdTHEqw/CNbBGjhzi7Ov/H2PnBW3zjaBQsaKDq\nlS3d77qOig6oxLDcVIPGcZ2hd+ln7SZhWaPoeu1HK31a0ghTjG3361w17CaV\nlRYn\r\n=72h5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"32ca9ecd27828d246877faa90f06442a78b3de88","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-995808e-1593027755533_1593027810754_0.44553079400116613","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-831d4d8-1593027800892":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-831d4d8-1593027800892","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-831d4d8-1593027800892","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"33ce47d970ea666fc89b4d1c302af9a40523a0f3","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-831d4d8-1593027800892.tgz","fileCount":8,"integrity":"sha512-I9cti/P9AvfDMlZeVRkFM52PObTy6rnwWsVDzY+PtvqUa5yy109+ZNu7qWO1MJn0Etx4QgEnxIF2+iVkxeo+RA==","signatures":[{"sig":"MEUCIBKjgrEO1icqGrj/W+G8j7Zn+wqF7gDU/XebWu9nmADhAiEA6csWIy/py1uHfJpiLlifyC382rMCsT5NehHmt5e4kTo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":38899,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe860LCRA9TVsSAnZWagAANNIP/1BsWBNe2+QRbbbwcWrw\nczACgv9vAbUg9gCYqGSLcLgQihQdubbHTMrqqmtUcdaxElPu3fd1h2/hG9u4\nfPVENnLaZd9OXdw0SMguFrjwSdf5hFfxRRpU6gyY2ZCsYR0ISJRVgJ+qu2oY\n4Y5v7oCoaVrDtnhNgY86r3wCO/VvkK8YDMEVS+BwDgpuLTCHRs+Ucv38eA7r\n8AEddITgElRgQgPA2IJySp0FrQiPifZCRuhv659HGVE3ohPdnaijDu3PzTPA\nlhw0gimD4zPdiLEGt1oZXd8QAod5PwmVc+YG7IXvi6tRUu0loObiPwmdmS4/\n0fIHIe1/bn8+4L/7dNqZ30cJ8/MIYuPmTNLLe/DJg4VYuHTiD2sTXFiGA5bU\nup8NCOHOEQsgUV5fn8FBa+JwVv/gh+tq37s33k+AbXeqd3+0kKCD5zS8k8n3\nKlork50qPebgXi5cSewtUj9rS52g9xjKARfJD8d2mF+TZxCmgkaRDvrovTgf\ne3nJcm3v9CUkP2CIYe6y+sUnKj7zZfwQeejt2cQIGcw7J+lesSCSFnTyjnIk\nE1jwGg569+AGifs5ZNQUSZlU6MajMf7oe6GLKW6zsZXcVzm6sSk70jZzPcmM\nle6eEwEA0TmzFmWvGJQrWniK2VKEJEMcVEWSWjOD6Q7Y1TydRkJjpK7vuscL\nSxz5\r\n=eRgH\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0bf1d1523063146d144fbd6654d3c18aed588b51","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-831d4d8-1593027800892_1593027851097_0.2096185791322731","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-e841429-1593027895970":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-e841429-1593027895970","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-e841429-1593027895970","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b8a9b677c425e673f21c67f743ef7c829400cd0c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-e841429-1593027895970.tgz","fileCount":8,"integrity":"sha512-f1lLQGabywrSpm2WpA087w01+QKKg/kfl2hZFzknKxWUUNaKEnXxdU4+j63CTt8OzXn4AE40BfallP8aaiHrhw==","signatures":[{"sig":"MEUCIQCGY8zEdoI0FL1uVrGM0NGcuTVAUvC+5ig1AElMD+xnugIgEOwSzytEP9A58VUgJ7eIuCs14mzqWcjBoKJ/KY+wO9Q=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":38899,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe861mCRA9TVsSAnZWagAA8LEP/jIiY1k8IMgJuF5gisoP\nrsfbQe/autChPXQWWChoX9BnmtLCm65Y6QqzYID+N4bMgqh/+xG1rGesP2OI\nTMCxf/dkItZ1R7uRkbIz/YHJ98F9sg0Y1NMTlNuqCqSjCATvpLj4c9RDUO25\n1uBl1lMZSW1c6GNhdVRBobKQfHjtl3wn93pX5iQmRXjZWhsKJO0e/MOGqefK\nemPmgVRZZ1O8zWVbNOIcktOO7VEUyJOMJyy0jGuRc7Ej4V/IkRT7HHC7fC14\nQWPUkaWKoqF/fTBdGMoZAcnUherdeV7PQ/hiE5XU5BiHNGrlHX7/bwG/wSkJ\nC9QrUjsZr+B0kvMN+m1nybwdgnHdV03sJPUmYmUM+uRn7/UTJuLziodIwo47\n2rrovc+3Zuu2beaqdmsNZkYrCoCO56XQDjgT7KFf5d24/59JVJWaopfnbD2m\nSCfuwyuM6RwyhqHLEE+uSysjqIslHamgJHwhQwTn6Zk4HmRruc+9xfMPlPRW\nyo7OSBbYeNxO6yoxQopItOc1ErGvx9sZnVeD5Kf1NuPuD5PYM0btyCb3saw9\nsYJHvBjKb5eDmF0kG+t/z+zXP+pyBzsO0ihVaqxJVicZIg4M5MyB/tKgW1TQ\nsJE15PbETJMspetShGWv4oZw1kKX8Jhobt2bVHHrqJV1lnd2DmTjbRDkH5Du\nDrcn\r\n=HDuX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"608716936d527c3f001d694c0a8aaa90f86eaaef","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-e841429-1593027895970_1593027942145_0.30942574645668586","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-ee026d8-1593028051773":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-ee026d8-1593028051773","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-ee026d8-1593028051773","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"2c0453c81bc64c7ddd92997164cfdeac1961f8cc","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-ee026d8-1593028051773.tgz","fileCount":8,"integrity":"sha512-eSmvLPgOfCZM4EmJliJ266JF1E+BVgEEb5zD7JYfAmwu3+2yTPWQJcVvoFXAFvUyhk53UUtdXPtkV1RVWihWPw==","signatures":[{"sig":"MEUCIDbqtCzBr/Oe+lEnhJ7qJv+pwVYJnsN9ho3RXN6gEMreAiEA+zZS11HjQKgKGFsHduUPCC0d+V547AbOhaa2xKcFQxc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":38899,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe864ECRA9TVsSAnZWagAA8rEQAIom+YcQWzzH0OvfkmJH\n86jPngpAwDcA0bVgq+CvRAB1FMYRWwuUIulf0VFmkdBkzA9YJXF1Ir1cDI23\nUeteB64VeO7CNCL/daNCupRh99U7tKhs8kJiT/6BnIS8JeU2sOFAoSFZ925a\ni4114kZQ5/8H+pLIFbR0A6+uafZ1q0mbQepmcebIHJhrMSgbbVIph5aRI4nK\n2n1hwqaj8oEOPQacZAn9SBVF7rzB2EkP2pgZRcJBfKlWlJkqi8fYs8N1hW2C\noS/urkvekc8dHmmjNW64yXzD3PR/GHjdDrdph5wtOteg0XpPfdxU8INLrkdR\na7mpMPDj5U6pq09IvIIP8gkoPaq7SP6J1FU6ELXTU9S+wfC+4/KldpBnA+qf\nSg9h+is7a7rwAzRkzouMVoYR1EEDH0hZnRYrm7KauVPIEW6sKA3l3NRa6MBW\nZLqgVeljDLh/Ghi/9tMvPxQoYG6E9ozQY0nJJbknKZE3X9sjN1fAnjBc01O+\n2vOCkYO4vvf74ewmyO6ekRjhHZ+af5n9wpn/cVCjYMivPUKxFVDLb8Qh5t26\n8z46k9eGWii4PGS/7T8eB2bKGrWWTTzXq9ndtGrEJIBB1erBQ2FrRbhZgjqg\nWLck4IYvCMiP1oODUy0xHffc9WovjzgLeXTYHQ9wfJoFHGGZe4b5CtIeW/rF\ndzPd\r\n=TpK1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"59df8f2b200f6ae0604eeebde33abb2617dd4594","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-ee026d8-1593028051773_1593028099961_0.2942953465935363","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-4cc19c6-1593070748555":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-4cc19c6-1593070748555","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-4cc19c6-1593070748555","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"2ac2ff58cd176f43e10990217edbab63369df78e","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-4cc19c6-1593070748555.tgz","fileCount":8,"integrity":"sha512-Udk6iHUgIbHrHoZFRE6d6baWeeemucZA56S3K6fsqV/ybwZAhpfH+lpZ6MnAdLk8OO6dTLl2WftL3HrGUBWDRw==","signatures":[{"sig":"MEQCH3uwvlmSY0cxEQNxsjyGnOnOOzcghIZZFwUuruSbsJgCIQDOcVV8VIYLjNAE5Beu+wL6f/Rl176Qi7St/k6hT/kHbg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":40165,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe9FTPCRA9TVsSAnZWagAAbNQP/01SQg6R4iBsoCNQayj8\nu3UKTkiGbJXDvuG7yrF7gSfLpRcr3WY7wLof6XwlPoJN0x9KPrDpKdN8Mfke\nfNhibTIPy1U9JmVMo7bfRp/JvmV6+i6g5+5soFi33K4BcCi2Tko/zGG1Eiqm\nmHilSmDZX7iWwtgtiU1oBOy/gH3L0Sf3LLrDlk66owmQFsz+9hWz0cX96bwY\nn519bIUFVegNkoBsbj14eh4DeA09eoGv6rM30/o5kMb/sUgeVKeXWYT1TJcs\nyhU95iUilUO9cKL7nPEtceXGs36Np8OnLAQl+IO6BBRwOgm3n02cUfMd1KT7\n0nG0bNRHyRCAJRDVaICZPQLQn2ZDr8dED6ffy8/9qlHpZzqnV9iIsoXgc9ZM\nGckkE5L3phZ61y1LrB+eEj4wjQ99ECvFTUlboQ02GrEsTduGGXt1DNvDX2at\nOu7cEroDJnf7LFaT6QYGRistSsaON/ZGBgt7+z+09VYtGXOjCWwiQF4Z/1TF\nJm8vMobw7+nJ/K3eYcvZK37bpYji8e5nUJi6vnc3RydP91pNEelOBlICPxy+\neYLT591HAh5iuyEV5F+vXiJeM/zpdBrNSO3kN3SiZ4JVudVzlcycjBxXYDCS\nIYuDg4ziG2GkzYcPzAAGxnuke89Dxw3a0Iw519CGLctnTWptnBkfJs1br5Zg\nMt/7\r\n=uelv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"230516f8740d3b92f92225c3a9775d4c729b3ef0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-4cc19c6-1593070748555_1593070798470_0.9262130698999511","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-24fd182-1593071590447":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-24fd182-1593071590447","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-24fd182-1593071590447","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"04f2b0c3583ecfea6b2d0bc2dd5729621265193c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-24fd182-1593071590447.tgz","fileCount":8,"integrity":"sha512-E3GHJd2ukTO6Akv0kHiX0H6/cUtNRjJOd750W4GnLxSZRrBfWu5r7/gubduYTA2etjt7YAEcN4RqPDZkIpWRCQ==","signatures":[{"sig":"MEUCIBVGBCrRW3E/TCAtF3bFVJCh3tkpSrX4FJx/oBNIWYbvAiEAgKquQE8HvhG5y/EyyzAiAy8gmIV3BO9TNSvd3doaXiA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":40293,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe9FgjCRA9TVsSAnZWagAArVgP/0s9IXVtEDeHSip2XBA0\n8ecwws6pDvOIJ3WfpNUH9tbn8j9GzLbZXGw2WeMKtyqQX3FibCxQ7wHPYO94\nhTtn3ODF/Q+TueXu3PoNVCTU94DJZDeW1z8/oJFVe9zjHn6K+dAKwmL1rajF\n1c9S4epg4xapfbcBbd7WvQKYjSaCj3H9UMGY9ly0nFQkoktHehBM8Istag8F\nhbQ/Qp3sCIyUSeZjbNyWjoi995XvWnqywZKLEGBm2L4+XKPCB8kqb4iFVFKx\nrqrDQPexpbw40m41P39XTUmJEj3S9r4dqKDbxM9Ew33xffr5BLd9wAYtMuF5\n4jiPMPzC2M7Hhdb63k/9K2SnsPCh3l13SnEtA/aiBk1qrzaaI2+uGcUDLn5x\nhtFMwfy26SxWyQWtpYXK7c6vYKuqfakqNWVPDMOmmKk2koI1N6tjOl+5sSWW\nrFgl6fQ8bogs3uUfC+Ig53vg7Gh2c2rznYWU6KvAb7/oFJBsNJeKLuy81bgS\nEh4MCWaqsNDqruSteeHm08KC1n2zhyprnfC+Au/Jl3DpPi7BFEph7NDWhUeS\neBAKuoDeom/w4RWzzvcR8nzaSXjlFPjfeZopoWHVAiSCiooVgBC6Kr71VAq+\nQeqsizKVn0vldMniKs8g1eWWarvUOvTiVr3LNQafWangAbx1xdMWnmG9u3dc\n7jcm\r\n=X8Ni\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"324605366c30aa77c070f7c9d78f296d437619fb","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-24fd182-1593071590447_1593071651390_0.4130258859871929","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-174f279-1593071762363":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-174f279-1593071762363","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-174f279-1593071762363","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ac939bfd5f1ac8073aff374299ce5d007663857f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-174f279-1593071762363.tgz","fileCount":8,"integrity":"sha512-PJ5WcK+n+L8F5mp3193l+yEvKebl63dX9ury8LZRfxdom1r6tAOh/MzIdCl6kwmZdJjjCyoUQXVmhmSPGEg4iw==","signatures":[{"sig":"MEUCIQDRv2BPPdbTr2KtfPOhE5vnRZyhWUOUHcbKs0jjVIkIWQIgf7ZNtZUvtjFzaAZTSzsdRKkk03p9x7ARFd2PzTd1FjQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":40297,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe9FjLCRA9TVsSAnZWagAAJnMQAIiGtXdqlhmD3STjT7SR\ndtcg4VuhEyfS0pdL3BkoT+SNn+1JjlZrcSMncbwloW7KzFTG8fO1Iz70i7IC\nY71xS6h1QEPI8wtbLwiYQPnedX87SVQ2ivWhg+ykAd72yNdvBRUGiQVanRkT\nZ8/7lSre3x6AFJaJmMWAiU2tawLOAlAcu9Mr8GLg9sKuJQ9X6gq2vA8y6oRE\nKCv8CwCWBsRBOFLSFC0mvAaeQo6K1cbEcfVASE3W1SD5aI8DLSdjQVg7mHsl\nNYd/eIO7ypHzhksqv23mjaY8uzc/5257I70Eg8LCmL7xNkGxwSzcbX3aPADP\n/1txHwihTJMf6CFqQ40bfB391TVunWyQB08cjrotk2wzxoN6q+XId1qACeMk\n4MXjpSz4Zu9Uk5Gfw8nUTCikI7m8XXEF4otU/Ef+/FbTtxT02MulUqwHX3sa\nDZI/5OegRMLxP5jj9g7JqSNHRkzqRmiF5kxFgLV175n1P1lfudHe4RYaz6qs\nrC1iQPSIsv0LozZJeWpalt8Jj42N78oHycbb7jDX92YWBW6NZILJXg5RgmlG\n7ocgKgQGmJeZ2ASRmfajxKzYxRm39sDXGwqEWc7j1PdClY1ejlkuVTP3yK93\nqOOi0c5pLyNH+1zlq2/SjPbcvCBUqBXyHVD4QjijgxLaWkkuT1y2MVq2PFGF\nd3St\r\n=zCVA\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0e7cdc9a0cfba33c64618dc37e3e07c5eca6983f","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-174f279-1593071762363_1593071818853_0.46361175165656276","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-a42cfe7-1593631888948":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-a42cfe7-1593631888948","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-a42cfe7-1593631888948","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"4903f3dfeceff0b73f1b23120f5562d44ffa10b4","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-a42cfe7-1593631888948.tgz","fileCount":8,"integrity":"sha512-VkoEwA7olRFvjgD4a2SIocUd5fG1Iws9NF3ZSJixE99VqiP1LsD7Qge5rUS9x2HiHSMCIGrhdyzjAyQKi6YUzQ==","signatures":[{"sig":"MEYCIQCfIl3kr/H4G7u+SCeTQMk44gD9TbStgrdxxmNbBR2rOAIhALx+iBttG+0kyRVcl6/f8bc5uYvt2q/BLfWDG11BQ/qy","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":40705,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe/OS+CRA9TVsSAnZWagAA+jkP/1t1hIVlamVuV84zWJzb\njGXi8Xmw/JtgrYWcGUx7sfieMurMLRBWl/E0NgDBmTKInlGGlE+z09SFGahb\nO1MeX3vUjIttqWT6z3mKVekGd71kuQUMk1Qr6qzIs3hKiatCXrOtJpbqSphr\np1JKLcAs6X7SHW7dHJwbM5AuPGjlLIhSDnILnGFRsA3AgICyzgzFTc7KnOq2\nZXGZCLmh09nSrRQW/eYxWertWNSYd4TSZKYx4oRWn+MQSiNZloNoUU4tm2Oq\nmP7P21g7nHp9PbD6JP/cMc6yDixKJ02HEDNEDejXA9TS/VD9dVznCMdIWs1L\nGvolL2owpEd14nMm2WP145fmoUlZF90RCAGpsCHy/RFS2c8NJC3UzsNdDv+I\ngs9SzKmS9Bk184bHHB1EzCsbctADKhc6nKD3Ck5RNxlOmuyE7F2qE0E+PgkN\n2kbTRQZHHROZ/E6xuPRxoK45of/eY7pUBbFCXqETbNKHBrBVlAiBZoMoIKXF\nTAvBGXncwLjN2AC6YVMk4iZ1UCKg6xbQFNyAvPTdCIeiA0JBNnydizBsq+vQ\nHB3Ek22/AY5euni5ewE3YNlCzq6hPTmPf7JamdUFSlynAIx7gi45ibuPzG8Z\nI87T1sXwFixmcRL0nCp5ArfPrlF39RZG48Ul7gy2aF6IFfBkfOiJROIR+9LA\n7sAt\r\n=zFNX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bb9c975444ab589e35c2053b52a2dc11e117671c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-a42cfe7-1593631888948_1593631933797_0.9878095757830538","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-7190ff7-1593632790090":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-7190ff7-1593632790090","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-7190ff7-1593632790090","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"6e47857d27fe0fe192e55f238346cac516d7c639","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-7190ff7-1593632790090.tgz","fileCount":8,"integrity":"sha512-itVE5qJyhzLzp/VWxg/wXyOFsaDnF8b/8yNtxwA/HXktgsb5ALmdA8MWv52qiB3qGLZHhkRXLxzXTV9q0UBdOw==","signatures":[{"sig":"MEUCIDjhBH+/iN69qPSZVN+XjcdV2M1WHqE9EZJMc5m2FhrHAiEA/liX4hIJkW9/Evo1dGtUYbctTja0Arv6NbfUELz1jSs=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":40637,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe/OhGCRA9TVsSAnZWagAATPYP/0eGDno+DHY1AglImMPP\nzKl2dbo+H7/DilSpCRUEN6VBLfOgsgtbhp/k1wC8PDbq1iAK8OGXzYHKmR+2\nKVaNl8scpzpiyU0SO/NfdVaCkO16ZZxo3ERFJEUs85EDI9a7SY0mrX2aQp5L\nNOO7sywyrcCbTKjsXpG+wXZ7koAnK9ossgNuqQ2/00IQnP/lps6sRfMj7por\nN/6Rcq2UtAxiBOsdL3v6K6zuhDhSvxyInET0m1BKDRLN2RKmdlY8bccecbBM\n5tLmEv1x14IwA8SHgwPiQAN7tiATZdOqSiieSP6zHn8f6RxKpabfj/bIGY82\nrNbJXNYoUc5t+/nWJQUHocmu4ZuXUHrsVO2TYJDgEZxK6IvNIWD7D/M4PTe2\nhWhZ6T05lWEE99eXZrUQrHpPQO8EjCXORkXjrjcF6WQQqC1pgMHH5jNn4b08\n9wf+IPwonTV6fWFV1ciZw4YPGU9P5F3hXZbKNKeBty7T8GWTGnOd+AVof0Ps\nZoJc2mMMSF0ovizGu5ppde0IfL/Qxzj4mtuBokcW2rZnrLkBgZi0fKAK4BBm\ndnzH11iNxcb7xE69Z/oFxcLFL7hd++0BmA11/ubaFI7Ozrp1UixekVymHThT\ns0eSSUR6ahpUMdcYp4WfKDuLvgMjiAkYc9OQ+78EvTNoRkKyUQgOSEjNiSNW\nIUvT\r\n=3VK1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"49aaf026815a9f77b27c0ce4eea43d4e09494425","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-7190ff7-1593632790090_1593632838004_0.20639550883685165","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-699ea67-1593685939770":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-699ea67-1593685939770","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-699ea67-1593685939770","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"4611f57eebf7d28db37fe56e98a8c0632e4272f1","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-699ea67-1593685939770.tgz","fileCount":8,"integrity":"sha512-UTAy0br4x20Zj0HHS1nCyS1sMt0U6517Z6+6yDZ+49wt4SE2011ve4ajkR0/PurgkrA5PB+5UNApzRO7DEaXOQ==","signatures":[{"sig":"MEQCIFTwWzcXvgBvla3twbWTnRppnjH1t9Qos552GPXG4IhvAiAl/sxXeGgrqDfqB/dAJUIN46wsrRH9ehFMzWKriLWirw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":41593,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe/bf2CRA9TVsSAnZWagAAzRsP/3LBOEjDlL3N73A+DLZV\nfiWMo/s2hRMmUkuRMP4kF+oGaOVBe4CompqBHiEMF32KoNXADZAO71PejiSF\nXUh3B8Vrw3FWgRj6EOK6j9vDwHoBCCZ07Y/jKheNFg1QCDSWuZubWkXjGwCD\n9eOWkPg4LCmQF3/XMYI1WG8uwR7DbmpaDeGNyjsE6oAd87VI/4znLm5ZYzXh\n3eOBkKLluTjPrqroelv8voNt1jsJ+v+hgHcendT9b2anyzmF5pud7kdGiXl7\n2/gYunlYkHC7ArpTw/poDHwox292ZP63mEn3A5yvOsQVA4mqTG89zU1BHih4\nRKzkQ0sWQ+c7OWgYuHfcNl7XRk7i7gnjBdjueVni0RSoFnXVUIcF9cU34QXi\neR2LEKvWsowxMp6Xtsu/yjDj4QN/0siC0248UCAAT4gLgAmt2GU8BEWEdemB\nMvlEP8gOKBsnw88LJDms77ytv2ydYmWi1NW39wg2qksIKy6kYMA2MIrFRCo/\nJZe+BiZ/gJDUzr0ueFGbSdSbf59JGJnZa/9cAVShRlUK8sN9JQjamVmmldw3\nDYOSUDgtFNI+WYEzokWfGWdWviGgKPLJ/EEBAf9tN49DVWpaVE0+xCOQ/+Vf\nHagGCkTRAGx/2GHDtY8AYw+0kcw99RJfJOFV98jwzFHQ+5IvyXwEvqdy+LNo\nuje8\r\n=kNxH\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"a68b2851fc1791ce89412ee28c560288abd67c76","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-699ea67-1593685939770_1593686005627_0.2546918748659288","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-5c9327f-1594021143089":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-5c9327f-1594021143089","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-5c9327f-1594021143089","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"686af0d95272f9751db2fe4e6a792619031584a8","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-5c9327f-1594021143089.tgz","fileCount":8,"integrity":"sha512-AkWca39JGl464Rf2wG2Uw9W0scXEAA+oO/oVUO8YmZpn1Rz1+hLRagcEK9ehdmvnxJsSKapgs6iqcCSKTBjK0w==","signatures":[{"sig":"MEUCIQDWsfsoKIW+v63Yfutl/R0BiftA7Au42SBbHfbAcGxnTAIgfjh+pqXS/VVsOJuGy6ZaxhlZxK/jbw+DoPuRb6IYgKE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":43292,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfAtVDCRA9TVsSAnZWagAAD+gP/1N4jZIw+h+NEDRbWliG\nmgRAks/N0pz26qQikCl6odTMC5PVp/ApqmeKjdOXf9fqF15X7vfv58Pn2Qo0\nUAhIShXhZXZkGbEUQPzKzuZcqdq2HNO1CveVNACnbS1jxVZH0rOMZ9I/oPRA\nXZgAu7xljJkMlPlV+OiyIyB4TE/jRp+g6Uqv503wxQcRX638Saba6PFOyYDn\nSVbZ26HqoHc4o/2J+Mc5vw+0Z+ux8L/wGBx4c+5S4nm4ozR7uW3IZZ160ZVo\nyRxrrL4wr2U6PANVb2F+3W9dLWgHrpOz+3/rL8fNFRwrI+tIz25RKxzccB6f\n+JF/YJDHK0gnkH+vNrL0NJk7K82NtGl6W3XX6RIEKBgs6mwdIH3/nNZLy+oo\nMITLCxNzS7KrHS0x0YP9asIKZUPJcz1eLRMykG0vDIWR1ImNi7RXVY2pI8x+\nQpBtXnoc18yeXH7iAf/YhXbc9H9nhKkKvDN8eJRrZhWRFmwx2jSCDX6zF0xV\npBYhiPbTftXzz42l06SshEmLKallbSx5yTgpYbCiq/Z0tX4GudU+H+/pyCmS\n73vo3I3OE76ohhXKgk2fogz9SD2zORo2utBqkc+qtpTmn+vHGSJcHyQW6ZrN\nSH39INpuAJqMoqM0SVcEGtQ2Emju2rM/b2K5O8sCxIX5RTgzY8G/9wxCbRQX\nbIEy\r\n=43Hz\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"1ce7341668b7ee8cba741cf73f8d8f0491f3a34e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-5c9327f-1594021143089_1594021187507_0.34319376882180097","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-421966e-1594025972328":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-421966e-1594025972328","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-421966e-1594025972328","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1147e3dc0eab6375907f895e7a3154a8eed5c550","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-421966e-1594025972328.tgz","fileCount":8,"integrity":"sha512-rBxf9+ZD7xytPp1E0rnUtW75UMrDNBNauutz9aFCcJzSN2ECirqVDPmBvcU17sbesBCPsXsEoTb9JL6R8ir7yA==","signatures":[{"sig":"MEUCIGtgPLeoUAxKz+48tn9uDaK52pgwYkL+IhAwYuf1+LdWAiEApMbARay17mO229HimMPlh/8G5Hf+fVjeMOMfv/IypPs=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":43300,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfAug5CRA9TVsSAnZWagAAG7AP/Asy4iAde2SqagLm5LS1\nNX5IvN4fmc8kzQ7p5+iEKUoyrn7TEFhPQk0YpiMq6mmyZjUnrSsMZY7NM/6S\nvvY4SzsF8AbvUCFanfO1iKISDj1eEYg4mkHh993iDw6z7AHNrRZW1H2euYDJ\np56GeLRolRRPYWDAoSnBQcWrez+WtC/J7ThWvSrGCJc0kYa4xwODFTuzcFWq\nmL5e9BtjoaRDm35uWL6tyDBFvKZb13bPFkVFZNHIzTpAehtkyGER62Wwgur5\nNMUa2vEZPAiGLKKk5IZtFiDuYVmzwF5EkE36CKTRqkRwN/R2ytVYradcnzI8\ne1oIsY/rzDDA8gQD/wwLr26zpN64/3XP9+vT/Qf4bvi+gieCJYBPVHXuJuuT\naduI71GdxK47TOIQCV5H7mgLStNcBy3g5foAa4mWS7zDV9RAdVfMbWEhYLqk\nFS6xmc6YjNNUa73j1mdv/h61UrUJqdWC/Q7wACkGhQrTMRitZRsVEehT6E+6\na9R9H3hNpAHDexzPNtt9RSeJSA4fxyIhWWF+FhuIWGqc3482AUw5oLA9VY5B\nsH6XN0wb1rDgYs7ZcRHVsG/XeBon2OXjySpkwdbtwR5CEFSk2d6fuqYPcop7\n7UcK+LXNZiyDU+OE8rI+lXjF3Wx6QNrJgPjycVuzjiU8aCCyqsWY8NJxbACA\n4HHd\r\n=kCt7\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"32f8b4942b3ac2db562a312fa3932f3c0296ea19","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-421966e-1594025972328_1594026041547_0.7494813357183725","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-d28001e-1594029060654":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-d28001e-1594029060654","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-d28001e-1594029060654","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a22b35916d2773c70b1700a4e47e112dd650cfa0","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-d28001e-1594029060654.tgz","fileCount":8,"integrity":"sha512-WP0ZLbjzGHprcWpE2ZiHMKE4DirusEAW8l7OpU5ZSer/W4pLbLvaYihKlAGGU/eJnrXilC0q2oUH+EUV0Lil5w==","signatures":[{"sig":"MEQCIBiLUlFOO39rfyVhW6/DqLULWIh8MsDVymy9DyR/jizRAiAFbDhNJeV0t71AmyhTOklo2ZLW2wMDxn5zK+Ts1RSqBA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":45506,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfAvRACRA9TVsSAnZWagAAoTsP/2B5mG3iNl6Hu30E2J6y\neR5TSFhWj4vRpCu9rYmqmbDeFk70wMeTbJeJ98p8i4J0S0dMC6zbCEpUq7vs\nDveqqrBt6abEIaKsnUXOXBHypnGFf1Zxsh+ry9Pa/j52DzbPO5qDRs+X0Zfc\n0qIR6tg73A+m3Rf0owcX1/Nzwz/ZfZGWIUddj6J8WXNLWVP176sfukwCQSV6\ncu8uBjpvkdG8dK8BitcrJ6+93gbYe5jXobhWUgjZy81oYrgJNVmj2VYQMr7c\nGCkf/7DgEHybPZsKzgbZkYwcf4S+YceMvpzlcaP+Kck62J74024IwX820EWf\nRM773+WKchzDAiPPqx8Jt+W0C7mju887pal9wC+HVvlIOPIvIE97SDFudsxE\nbXcyaHAvyGfCnbGm/HSldpEWGOIDTNm7mEbReUTqf/fcsF7oRVHpYMwlpkv3\n8r8ZO0AnarCDuHjk8pF0m5RlfGR2jEHhdqiReJjxOxWsfUFzdf7/pk76ua8c\nxX+YTnTc04y3bi1UyZ2oeeYYh5gJahJwRlfnL1dlphwXgtEVrsBvaUZ41HD3\nb6zTf3mX32bJNNw3Qk157DpU4MMhTASybUWRrdYfxJiE7ot/B2T4d3nwEApW\nh/pLKnPvCmRahGgdPGabMuevHe4Y69F/HkMGtd8z+uhjljrIEO771OkDlWDS\nl5cu\r\n=VVk1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"13339ccd23fd59e975b78d6e5432982f3acfbcde","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-d28001e-1594029060654_1594029113096_0.5522884863368351","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-e0d08dd-1594029765669":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-e0d08dd-1594029765669","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-e0d08dd-1594029765669","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"d3340c3ee43a291b6ed96f56d922e47ecb38e761","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-e0d08dd-1594029765669.tgz","fileCount":8,"integrity":"sha512-oY6IaBweJbOgLxqn3VeVzh/USD7iG2RN3UDfj74jHRAvL9OslsMkHAEhoAPJ7xyzl/+kX7Y2Z+fySgW2+1ME1w==","signatures":[{"sig":"MEQCIDGF+6oscbG5kSNDqG0Z5jIch7ZKyvwXEg2IayBxGYLeAiAnST58RWaHO7lUM91mVkJPLM6Y1v/1JVflhYV3rRcrAg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":45510,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfAvcICRA9TVsSAnZWagAAF8YP/A9tyn9MEVSTvtEJAwW5\nX0xnZ86YikCRuGBHVFMjlFrHXLFY8j77FXOhc34aX8+I/RjhMLErRnlggGqa\nEJhM3/AF11LrMDz+DHK+M/2Ku3ldJ3WGVQTr1xG/h8AFw3I8oUJXqgDu0+Fe\nlmqIWFz9sjhApTMQR233fO7z6gn785Wy4NZjcEi1KJ1OHzbIKZ+tvclnIsMZ\n3OtGjM0pfmHskNDZyIXthAuZH73KEvQMZ1LkCyvEiixIujlU8VKmWM0eQw2T\ndqmvEXReMWbEfDdt0PwdBhk2FYJXjvNlixP+AQKdiXvofmBcMnYH5pRp6OOY\nJN2eheADPZwZh7Vq8WcRef/0ARjZngcPrm97VVMCmY7U0tIo+vixZoRro0N5\nNHXaPYwH0xVvBmCtGehJ8qiIwkZBhdeqSPq/0bY4E0YImv//1KCL7UFoXTES\n82VmfRbuLt4Kwo4srbCEJjrKnHSYGv2uM9x4x/Tw2O28swhMNpoNj3SAbfjK\n37Pvirg2jAfidj52sOSS2GqlLSONq6dtLnYSDTjrWh2RDRmSXvrXOJCHBkE5\nnP6s/qWyihuAuCBQAQONiVL7yAKmjBbPE4PsNDmwDoJObnvMDxL+HyETBnkR\nHOmozb7ixCc9KzPQ8bAERvNJRezxOrNxfId5bsBTGiueOitR9WCOrciJC9Ev\nMRam\r\n=JZPP\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"1cbb496539c0b31c28717c005e3b150617dd0a37","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-e0d08dd-1594029765669_1594029831988_0.7462959983667548","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-3dc161c-1594033988458":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-3dc161c-1594033988458","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-3dc161c-1594033988458","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8cac1c1d75bb678a85a101a4f8e0808265a62682","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-3dc161c-1594033988458.tgz","fileCount":8,"integrity":"sha512-P1gmv5Hi2+0VN2Di5Dprra9hrMhn12O6thZYQ90/VoQQDazrMFWQIO1W+j8zNZO/z6hUxDStXUWvcFK0T/Dwbg==","signatures":[{"sig":"MEUCIA22Hn3RkJHmP9Vg6nDvf7cxUIXe31oSkF0HJVdGDnKkAiEA0Uynk52gmTVWMnBhyUV2IuBXIFJWg+IrJ9epcSQdew8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":45490,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfAwd1CRA9TVsSAnZWagAAapkP/1qPsZ3Jg9i6i7lcas9D\nkToeWGI0DAPPaWzjbsSR1fYHyViyw6QXP3V35hq1Mls0wD9RpbjHE1O8AM+h\nBUCKIFwtQRoU2FQaHfd+djI+aYS1PjcSxudmQiKTYXHI/f4WsjYQS+c6tHHh\n9LjrNfDSeoAgqb6YwSQPS3QWUQYTJsGoTjccXjNjKcwTT+IUFGtBXhyQvK7F\nssbWUxekI54sezZM4XowsXshovzbQagYwaK1/DI0vWP7x+XkpuKOIZZ/6SSO\n0enMyPuB/R7H/I3RG+D1rIh4VpCacMtilkzrQ7fxPUGCfIXnwFMcfPqXb/Bl\nK0lA/wSjxkgU5KAGkkSU0TlAGvKZ9SAuiNRxW40KaQm3SBAFY/xQKVzOxRkw\nzbSA3t2DEbVHSvAMbXJRN4RVAFqHix/mtIuhglwi932u/11tL6D3XjZoW7f7\n+fA5u9uAP1ham9jJxqLhKRiz3tVjS3C/JFI4hf9PctvUYGdiMVNjUVvey9MG\ny4kIF00VtVlFpzrrZk3BipyAyKrnJ4Z9IhGQEgyDcAKmhvqcHJud3G2+dAJf\nrq4VcDMvW/6EiP2wc+1kXpZnYD9pnc6V/UvQUEVC0+oZB4B36RDt00RKEc8G\nDe1LzaQuV+jRBoMgm6OnhdjRWW+nIuFQKTdgmicdZk38d81fkvOSw4Zalgsf\nPju8\r\n=IIcA\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"3be5337b96da5473d28ed02e4f13cbc9bcb308dd","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-3dc161c-1594033988458_1594034036513_0.8389662836513254","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-f1bc93a-1594062142098":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-f1bc93a-1594062142098","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-f1bc93a-1594062142098","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1bf6dfb4970585a7c19f55f080c0333920fe5c41","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-f1bc93a-1594062142098.tgz","fileCount":8,"integrity":"sha512-IE6J2i/ZKiT64XAkFo/zZWYPVMLQNLJ30HGF8lxSATcnJOnOgRYUFwOKfMb23zzXJT0iWtG2/KXEOvupt3nXIA==","signatures":[{"sig":"MEUCIQDW88nohAeVsBi3fwIfElu3kwkfMuXEKtYomP0aqGDIugIgPR/kYlO3E4DCqcohSeGpLYRaYqyqvyDdq+WZrW1JEOY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":45856,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfA3VzCRA9TVsSAnZWagAAsRIP/AmcembUzsdDHqMSHG2K\nsRwdijraCAFRChvocUw9cNhCHNVozloOCui8pF8WU0fGAxL3GEzaC5QD0Jf9\nhDk+gdIIwZoABRovZ3FCWcmmb5zzuBkXltRahp+5Ra74Izr5KkD7tc1Wigxf\nVNz6iDtkGf5SWDP99NKdjDlqM3nvhRTgU3LDzNQJIyXUc2itBvg7EK79ua3v\nSC2eR2OFVoaD01LNSPU3sEInLSnYYXY634tby6/7wTQX8hD44RHwfoDeButl\nTp9Wd6J2p9fS+Y4kDOVWZGPzQqDsVxsKbbVYZN8wZ5xIEoqTLTMIhxOSPUdJ\ncOIcvq10Wond8zlnGh4BtxgCUzaXq3skiByWoqKsBG9vD58EaLJUXltg8HgE\nEo5Eo8zNaW47anVVObdC7PNFRwY/RwYPafH+AMEOmU7k3UM+Sile4p/l7U8Q\nYAzwXV/ZN+icTHibpwupX/ZrNNzVM+H01zmi40XsvwEQ9c9uZJTQpRq3EtCy\nM5ATu0aRDTvjCx5J4ZoeV7ffP/5xtumY8+NzQqBGvsmK65mGvWxt6F3+zZ2l\nd/TCaCGt2aO9sklzOG9ZMZ99UBlLTCdnnqOVaKKrac3jUfB2AKSZ36whLOwU\n7Dp0ZuXXOI8FUP7uD9YnAwME/9jvum9KOhVyjK9N1RSDZ1dmgvu0BzP03BmA\nTsvr\r\n=NBE0\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0e5b0e4bdb8142ceb2910e48cdf1649c00a538e9","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-f1bc93a-1594062142098_1594062195294_0.09859948830849175","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-6350a5c-1594114758951":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-6350a5c-1594114758951","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-6350a5c-1594114758951","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8f2f12c9a2d2f23338cc03e2961b5e2f5ad682d5","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-6350a5c-1594114758951.tgz","fileCount":8,"integrity":"sha512-TJ9j+Hkl8n7G+Rm3k5vEG4rgnGphp2AQ9rbGyQHhj+KVXYhf4vy74gjBoLO8ygAXmE8q+tJraDAIogkw+i10NQ==","signatures":[{"sig":"MEUCIFjGpF9ZPiF9VQ43zEFf8svXp+wl6EFVAG2wOid1jTzhAiEA1hJSpEiGE9xwH0nxLpbDc9UjmoSzPaaWdqbIXFzQPds=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":47149,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBEMHCRA9TVsSAnZWagAALEIQAJppNu4+dHDQVGLHJ8/6\nBSFmnlZkz5BPSO3z2Pn/lLupu+t+Twat33PGPojlPsOJIqQoIThzvndyWi27\ndM1q1NXbqZQmKRUEyE0q1ral0/EWyZzCZo9jYHiXMHxyHC4laagYzBTLwvZH\nOsyN7vn0zr0tD1C9ab6L+2doPVimbubmH07Zr2iStEIvWPofPm0FHzZ6VAET\n4yYfcYurz3WfFd6+c7W9r44JOeV3POaN/6pPGIeJGNvkv4P128b5yiATcWk7\nrubwwa8aqn/eNvG+xMYgq67RkIrP8oJjS4dvDzMlDHzjJ0KLzKkqNkPD+Nvo\njpA8Ntfy4Is8COxD9KwAYr9qSM1UTJ7WOLuo5ka0y45ewyS6p/x+vCBD4KRj\njdb02lreXm6e0qetWwPS2euiLTJOPwhlLQLufSCk8ndlrF4s/L0wIyqgwzar\nES47/SuieL96+l4TXqKcS8b97w+aG2jPanIp4u4mLX/eVRnqThdsOQWryBY6\nob/qpil76EkIEM9joG7FqcLePpSRzDc2v/O+IAub5uNZZY8G+xQdJYEEy7yD\nPG8scyq565LzNvL9ylmzs4jc/oIDo01GNtEkMUO2hZXJkCIGbKt3MhDx3+Oh\nvhPn3FAtegh/9DFAMViLnpD0n9BZi8NB3qqjjnpR8YN65qJCTUaQwZ/yt8QO\nUvYV\r\n=1NKe\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"35fcfb9f42f1c5b82f070af8b952368711a72eaf","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-6350a5c-1594114758951_1594114822948_0.5100338065743146","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-3d46d79-1594115666859":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-3d46d79-1594115666859","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-3d46d79-1594115666859","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"be15ce2305f80b07193a8ac730584ad7d1127b26","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-3d46d79-1594115666859.tgz","fileCount":8,"integrity":"sha512-DFB7uwjasIy+NsdoAhBwIDj875z/M8rYP4Nv2xLGZ36Oj9MHCy2Woe/9soLHhUPC4AkWR8oACmnzP8R/D8b6pA==","signatures":[{"sig":"MEQCIBaeJSByYY4MW2QgcZdODDy/FZJuZR47ZEqFnwjSSNCwAiA8O+OyvkCAchW2+TpSVHaZs0piaKzohqC5Nt+DSFpHBQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":47237,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBEaHCRA9TVsSAnZWagAAdYkP/04Lp/OxqnTWQ+FDELqe\nsuP+6hPBShMHv1OMJPqktnD4vcVjfOst1mHXv+OShxj0UvLxA/fpAhfZ8lRZ\nEu+YPCaM/NYr+79T2cDhpxdO5AQLFaQyxJjxtqoof8lyIhfdyEWJirKY8p39\nzqw9qHp/p537q4LakiaLmvXJnaDDSc7XBYRb5UPS/jT0p79ECDn+I+itHJJA\nJrOAsnq93ffiMBUYLDpWlKwgN4kzhGbDKo/INevEb46WjLQdqmRZ5cMtgOer\nqvLWUSyfmB2JXQYzJ3TwqOAQzcLy4C7YZ6WVEdSzfoTJi0CYI1riCI1oihDA\ntt+Elkvxvql7NY4LAWjxU7IKBAgSn2NPS5lAeG2trPKcuf2n03LKvKZEWNeY\nrJwP6T+7STeTJG6CNKPoi17YEXMEFzIYOP3HOt9LCidgXHki+kYXdTwo8ARk\nB8wVu7wc9T895urgy8arm9wQ/JmnKr0jYJjs2ZYZ2/aFB1fAlSh+fSmIXhzZ\nH3ESbEWdVbrPi+Y1e/BQ6N66fK1zN2mJbe7VPo/1OBlR9oDAIbydVlQJWrVe\nZFjYBRCxWP4KfCcTpGhogAJ3W3HBN9bX4aYlUJRiGz1ERCMymBzebRHL5OuF\noPrLetp2eNDtoaLGKvfkdaLGbyM3Liqar29n/Y0Ly4EBZdmd6vY+cA0z/Uj3\n0HrB\r\n=rKZW\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"04a31168f9cedf6d57152927ceaa32cc7df01b1e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-3d46d79-1594115666859_1594115719229_0.891048844240111","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-88da17d-1594115772168":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-88da17d-1594115772168","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-88da17d-1594115772168","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f6deea566bb023a0f45633c078d0007477758495","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-88da17d-1594115772168.tgz","fileCount":8,"integrity":"sha512-ogYE3VmcNNjDMOHdcRPwFCXVZSAAy/WqJRWAvribDDxc3O0jDS+dwBBRGNFwlDHFOIiKGJVv1aoQ9j8oTgg5OA==","signatures":[{"sig":"MEMCIAp39E4BuZpknO/ZhZJVP0Ov8a/9EushsBrV6jaHRYbKAh9Qu67moT+w4sK6tX8JeDZ/8FGE9Ty4CA0C86fbxbqP","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":47237,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBEbtCRA9TVsSAnZWagAA9AEP/jY9/Tim2yBfNKB6F7Ob\nbtPXeruTnz+avssGR27o8TgQjnIMLmJtd4eiQQ0nURTYbW9YtJ5vOg1zqIpj\nwogOWkTm03EztSUtb9WMwu57D05QA1gRo8b0EemZqR1n5OtMYAzxdwDLTsNU\nJXpuyLs0yWYOacvtkPskJ4mCa/bcM/GKnV1awQKIO7R9Iu0cwooGtkoq2jG9\nnAj2pHPsImm1K8QA0EdtyU9EY6SToietVeUgced0pupZsCmFQjX1vY9e7dNR\nbO5RTpu61MWMHCAO+RRxOTfWmlani66TNTWv+Wc5SRzUwyzrEI2J18xkQUJu\nH4efwky/NA4QmgzcE2GeI4LDgGAby54ZAy62p+lK/krpujueb9P2osp3AzqN\n3kBJQEMsOO3wTat37xbMzydd1391DSnAHdI7aLUwAmSlRKJpUWaGCJ8OIHnD\nVBnD/SwKCE4RzRUZpBRLlR+akYqYjfLlQG0YvosHktQiTkoJ8Ifiq3Or7BL5\nbBh3Fu85pC0AKW/WIWcNaF2sFB59qQ+xdaV81Clciyod+LF4e0RlSykLbw+o\njTRophG1FEACKtKLFcfYu5vT3ySE6Qcy2SLB3Hj78Zk0bZPty6Dw7YJXFc+J\ntqjn7NZ+BxtgLQXiMTuzAF0O9b++h71wndjF+AAn3536WIdg0B51eKC0yBxo\nhdz6\r\n=cWSP\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"e56b395a9a76a83d3a1045b26aaceebe002dc2e2","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-88da17d-1594115772168_1594115820578_0.19152018198449938","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-875ec7e-1594121737141":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-875ec7e-1594121737141","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-875ec7e-1594121737141","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b9813d9640d4764332c10157829059f5d77ee859","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-875ec7e-1594121737141.tgz","fileCount":8,"integrity":"sha512-wmn1tN3UjglnSU2Sgl6f7tsrzDMVj98VeSoDWVEU+1kc4dOfvEFuV/IJZTbAwryMXwjg9eLeboik8SjzWkzxDw==","signatures":[{"sig":"MEUCIQCU3PMnMyXnOsCyJM62NVrZ1Rs9o3jq0Ktblbr5+JbkHgIgdY7t36ZCce9mGuv1F09OnjCGOZwmrX810wze2b308lw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":48607,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBF5NCRA9TVsSAnZWagAA6YUP/ihQ+T8OFgUNTnbMOxep\nZ5uslGBFfPTHsCzcdc9NKVcSkb3TrTDFk/hT6jP87qbLR40W4oeFV3Wff5dv\niFPMfHgtUXfnhYknEujTlMFXOzX/4XoLGTj1Eou2Aqut8khjEgUTYWGp9oxv\nQMZo1vAVCfoVGsPcIExhHjVpRXveE34JzOxDjYYbbZg91h3wy8mIBYsKotAT\n0afv/H3OJZOKs7Xqa/i7qpTRQNs88lXGSNCKVv0zcx7WG243qHoKkqKE/Lls\nwKczGXlrKT9xL8JDT8BIYWKSdcZ4pXjKIH6/ecYJ78S2oMXEdIiknsJkJ1El\ntW3HOVoqbYbVPC2NqqKlZYl+xkOrWsyvRmE/fiSe1xFqW+1hm2rmTMX4JFk7\nT+0N7bHEZZuJgi3KZuIfuS7GJ6Md8TAv/g9ZB4OwQBCy5o6xGLav4teSZ3zZ\nLryLxr2yxN9yTf/U2DyM0XxEWeGYicYZB+CcN5sHqQQidSdXaiAPh+XPSO1p\nApAhlAubdd8gqsUVoIo8HHtMJiJhR+pFwdGDYgoiY3JQ/tEATRAKuEnmPJJ7\nYrGvFZg6oMlfJ/p51Vmg9qQUn8CpoRmk7Dq9t9AAvEc9SSDR+nCL+r36eqR5\nyfFRQSSmMQVnEoEkKHfFNozzO0/8xK1zeJ9TgIf25zXSCauyuMJDqDWii2/7\nKS6o\r\n=WW8H\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"fa99718de1242cfc873c45808dd4ea2b373fa2b9","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-875ec7e-1594121737141_1594121804766_0.34208262782476995","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-f4b6fca-1594122413614":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-f4b6fca-1594122413614","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-f4b6fca-1594122413614","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ae9b90c6a0d75d7208d98d96925b4d9dd79389fc","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-f4b6fca-1594122413614.tgz","fileCount":8,"integrity":"sha512-j+ByUQxDKSKRyWWROBRzHhY0jTXlagWkpQlIUR92m1omrStgOTcs8m1HzoFSpM59Nep9cvxNdIHdQcfz9CZwoA==","signatures":[{"sig":"MEUCIA5gDh9n7YNo3Sg0FJ7PQkFmB9W4MRepyhyWnrOCQnQEAiEAsh+/WKw7fE1HKlmVTCbWcWNNmAgn3wNYwmizljNjSKg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":50474,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBGDlCRA9TVsSAnZWagAAyhcP/1OBmVSayE2KUogIZB1d\nLZKptORVdxg2ypA/8jJyD+KdHSa9CF/sIvMPT1AektvlkqaCk0BWDwzg728H\nuQ3VL6tgov357m7Sad083hvpjN0AjlZ0sXXMZURd+Tx2cymw1tTJWM9LcWb+\n8LLfBPWiaNvwdRkyRgQeAFFXXPQFZaIz04edw+fFXvx/HSRO9aTgVsugcKkU\nBfB6fetmZpM0WNCc+YNsb7EBQ7SfGQZq/R5n1ZV75tntmoOE3mhgd01b+vPr\ndEXFGmVYqjMMSvcFQ8Xvw852HTPEBoEFUuXFalNuZCHPwhCQew8Nx83o8L5b\n3iNY8PkHozIKwQt+AULqJyn7QhEe254W8gL56id2tRN3Hbg5hG0RsEj9qIrW\nFqRHK8dEJhVhVhuRtNi8d8GcRdrUT/lgIq6LeilSkAmioWcw55k/ccvZPr2/\nbMvVooZQKwCG+AwgbJCFIL7hZks1ekpFcdTJLmEhqWhWZfzUJcieaAjtU7oj\n7EYRxLKdJDHnw0Gl2FH+LsPcYAymlah95hies1yryyUq/6oahB3CVSQpLObh\n8sxsycuSlr2nmFre0ugAYSiq0b9P2Clg5IVUyHR1IFy7jA1FOcQBKq/fDHpz\nMxjIQffm/QD2jUgKFU0wwelhMumvqTL//4p++RDAKZMjVehnDslxB+5xnf84\n9D3P\r\n=IWhs\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"33edd67fa98f6154686127f3622534d41f4b163a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-f4b6fca-1594122413614_1594122469124_0.15727146939984005","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-4546cf9-1594145193712":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-4546cf9-1594145193712","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-4546cf9-1594145193712","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"9c47e03c1be4ab68232e21fe7bd061deb0c9aeb5","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-4546cf9-1594145193712.tgz","fileCount":8,"integrity":"sha512-GYFFhPejlekT2rLEVKG4fNTiF6ZCnUm/Q9vL7pXi42mV4Z4M8nOD/RK5U7WFOp0fX6VEuQ3dR4U0/oMnVxUj1g==","signatures":[{"sig":"MEUCIQCSSxhJYbJ4ClG7sAXrNNTpapi3fI4TwrVnwURg2D0ZkgIgQkwCsUafJdhg38mpRhtfCa18IRzY53VOG9IQe09b5Kg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":50294,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBLngCRA9TVsSAnZWagAAbg4P/RJ7bhCbKAc5mU2vaBzo\nV9MVDQdkoOY6rkcTV68Eg53JWhEpNi+zotmruOqC1WXLwxWMYOcsFpP9i9Fx\nFcLc1lMVaY6klsIyYkB08RqSVQJiJzVVyaSQzDOHjNfx3d8e+s4KcFBkhiZu\nQwhoGjB1AFaiaHZQ1EYudXGE6Zi65my/ge9CCQyp7TZhobjbboF2d26oWvGp\nS/ncqlp1LalZwzkNCVWsB8e6TnPixPiO9NocxqTtmmjB25HdjYnwJbE8+SiV\nrrBiw2lHyXt/iYtsLNVCEQ3lkIFDZw0739bTiZ12q+rqH8Moy3B4cftrzc0J\no9BjvDmdJZ3AHxVQSLnSnpHgU121N9tPXEUd92MnUzW7qwG5lmrCo8fYrqvg\njh7ObKppWHAC+a4zvbuCd99uVL05mDHEmuSot7ME6YqhCgezilDckoHur6jV\nmc1/GTuy1siO/S4kkW1EQWfvCGsh8v8jSPszuseSusKQSF5dgYPzbCUVmQGo\nOu0IlgQlYzC0EMHQN91OBaqo0mYqoOidG86VDyUaWLL/SkmzDiFLu7muUa2Q\nk6Pu5z/hi+p5vFXJjDcGXs4/SlojvZwQH2dKCwbfGdH1LUEBBzI9y8kq/LUC\nJnIYxIDniQp2QoWONWDPIhgtLr2Z4GmHmckIpyZ8R1WhKxYkbORkDvewr0zz\nVqRg\r\n=GhDV\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"85cc32071b8584467c8ad21438ad289a1611f454","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-4546cf9-1594145193712_1594145248056_0.2803070046824767","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-b2db077-1594146547980":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-b2db077-1594146547980","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-b2db077-1594146547980","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"e2554bdc5df5aa43984a945978b475ec67637dfc","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-b2db077-1594146547980.tgz","fileCount":8,"integrity":"sha512-bui9sJ+vifkA1yriMR9wxPXnBdjc2dG2PU9DXCaXdiI5psyCmVuIzqQ5xWRgMdPlINtUWcYoBPYxlY5ThXtvJQ==","signatures":[{"sig":"MEQCIE0GhqT3xhvmMzmzCh7ZLL97Mdgax8QIWV1TDtYflQAMAiBSo4x7IrwV9VFizEP4S7QMFMYijVbsdiBDF9b/E21wrg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":50308,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBL8qCRA9TVsSAnZWagAAXIcP/0/tlX3SrTkfezHCNN7V\n1mOxRa7lwhDWYKGMB2X7nF5Un7K671JIX5zwULozyylUoGnMQ3Hes8jbgrPF\nmFMu7cuyO1QGkRS+sIvrDp+17P2oNpQyNFWe9PRDm1lFYjd8Wp6sfD1tBUW2\nrkqTuCyZjyWJPpD/5ESyNxe9meXrmpXcFTFUcLHM0HIjkJYITFx7o+dBtkKN\nOQrfIQA5OMQ3RxZl+/oGbQHihgaEzcc3XAfnSbMtm7HeCoBgkvG+C1Jto+QM\n+zhhCZVzsM9wjDykhSBv/25rWS5BvMFKMqNwvux4lhrROgMLQzx3ICocUY1Q\nSWSLIRWy9b+1SJJVQaXtEH7mG0aBb+quML2pFHQxO6dmlAiBfqgmz01ZYntw\nFvXbv3ZzQ86G01sobw5xNdMryp8P11AV36FtfmR3bTxxi44ktl3F33w7AJMF\n77qTsOvH1B6ehxT6/mEZs7dVnG1GyeRTwXKFYQ7LAnR9bNCvF9Exgpx8/Dhq\najEzJS9DMjOxXmPBvBpSTrJl9JneFExzrifS3kPez6pCTFxj+Tx376LNSV6x\njOzrkGftZHybqZDIsxsplW1Rk920+ZOrbL9FV4mwcOVUwrtbaHYNHuw1GCKQ\nuZyT1vZDH8up10LOBzoFRUYZLayN+5OmsnO1/oB/1KhV6KhOjC72efZ2lEA/\n8P7m\r\n=88ZX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4c2a7bbcfacc2478725ed0e1b784b4958af3a526","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-b2db077-1594146547980_1594146601636_0.46265945495308913","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-da75b0f-1594148105144":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-da75b0f-1594148105144","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-da75b0f-1594148105144","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ddf231339af522be6b206411a635c292594df836","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-da75b0f-1594148105144.tgz","fileCount":8,"integrity":"sha512-SiY59+iMo6B25oJF6mebrRNmWxjqYalBgsR7uwednx0KocsQ4KgOzi83KZHk2oznwaHZ4t/ttU0eZ8517ykWBQ==","signatures":[{"sig":"MEUCIAi2JvoJZNxjOV32Avr7/d1gnPnGlsr3WkXI3k2mElkbAiEA/GmbgN0to20Mm95bPzvbUeCZVtc4EhUlG4xfxVqjeEY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":49322,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBMU+CRA9TVsSAnZWagAAqNIQAJtFVWsxrP3Uia9OPeVH\nuauY6zwPJezMUeY0KJkwXj9UETPd4hLQ6lLvvhsaWvBbHjltfyZTnYpnArZv\ntb/PEpQi+ZVFMC+hhyctgM4lewbIPFzn+W1Xm3Std7VOh68zEhDm3Y8RzidH\n7yZ+iefdkdTpxyHq9auQmy2rtxjvIMtBieHNfiFjReMupJ4QCC9qrEe/cc13\nZyU3Z5tGgZ9prWl6asc4G/brjRyqOD9d9rWeI2QOVkRrE/cWogPNoCr271wo\ntqYjeObGVX+HLAhOvgqHmsPJYrYmNZJZ0nQWiOBl2XSxX9Z615oLrfZ9yztv\nIFW6wwHX7DncO9dUs9/ZoZWHyuF2qvzk9w9vbNdDShHR2f6qpljBG+9AtR3k\ntsjPG8+BlY5eHYf9+wHg1G1oTdr49AqpslyRoQIdVWFIJOPvS60yZF9ZHnx2\nkJN91YVMz+VrIStgCSPI0Ka/Kcsu+fz5EfM8Iq41QhoI9cdal4CQh329Kc/c\nS4zqLXoeawKbrNoq2qSfi4Pao6BCaB4yiJ16+RAaBUFKqtrtW+glxBEF2Vgx\nLZaiYBnyLHGuX8IRbw6B96ILHO//z9T/xqCWeZRKshimnLYCSB2MZCG4JLZD\n/vP1nLZpIVuEl9qcOR9HTlsb4xEXKh5SNnV+MP5FZXKWR5Km9jL7ioSeDFue\n/3sA\r\n=K+q2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b5f705a684621b0856cd2af9bf6beb3e08fa7e0f","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-da75b0f-1594148105144_1594148158128_0.5389292173561366","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-90be954-1594154163818":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-90be954-1594154163818","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-90be954-1594154163818","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f6771c1f23342148801fc085049b2fcee391aed4","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-90be954-1594154163818.tgz","fileCount":8,"integrity":"sha512-4ohkBwZqi9PM6yFf91OX8eOCpsqf6QYq+8LOnFyDrARPsLo6QoTWa/ak6flmXS/rZKd+O7aTOE4bG8MmoiQcSA==","signatures":[{"sig":"MEUCIQDwgVkS/Cz+2OTOVcsbydwjxcD+4i7ZrbDuN3QARp2wrQIgIgLAZoEvURUS3aTPdWnVp+U+hYqdoPFV1GGbWigSZds=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":51940,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBNziCRA9TVsSAnZWagAAjY4P/R2NJSq72kyRZ6OVo5Fk\n2mO+HTCwFrhAuMKWjomGnCperjQoPsPRqFd9UqneWHSQpEorJUhaQEukRkY0\nYgqNil+5eH4vrar5Jv6YI0CrNFMRfD5uwIVWDDpcZN28A7OTQ3lWb1jOiXek\nWb91WXv85zoqN55Jsdo+gqNGcfRg/deInG6MJMDGrAACkyQJVKkcb5FepuxE\nuQFsTzDaSiLFOPqWFHaMhgAKe8oMcmpebTppRTecitcw5KUwdBekXu0LI1vr\nxR80vDNLPx7rdcWzBRfNz2/oXBax050F8nGGWDmJmzaz5HE/fL2t9HcsDxk2\nHkHs9nlhDZQyV3XBg6iaow7e74c0SRBFOhJ0dEXzRaqdFOgL91Da88yOIs33\nAqTRM+KBYt+QRXn0/VVjoe3awer/rcKdLju3jlSGRha+3y+4pUv3tpoytB6g\nXPaz/MBICgtKHAQcOQqI9UzWMQc1ohKut8xE9G3kB34Pgxs4NSHXAP4Uvwv9\nRmTo2M0NMRAJhyxky36O8bPYGaQk4NTiUlfcNRQagZKLw9X9Sx4cx6DewCXc\nXcjnamGG9pGAiXYtN12psg5EIz28LwArVmH6K9YmdWdHNugqhg6nmqa/TNuC\n5/TVBC3GPqedcGsDQeBxDipSBW1fLW7L908in3mzWnQD27NaRGS3G768GuIX\n9YdE\r\n=9gsc\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"6faddba0c199092ad2f9ee06c98253e444c04d65","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-90be954-1594154163818_1594154210161_0.11558028006317134","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-6883f82-1594278097863":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-6883f82-1594278097863","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-6883f82-1594278097863","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"6c4eeb5e061f24e0e151698d4be20cd661cabe7d","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-6883f82-1594278097863.tgz","fileCount":8,"integrity":"sha512-IxTvH0ONI1+X9mYdH2BnI9u40Hf7KWF3aG6D1dS9eEXXS4OzgoB+xqwc5YetYyWKozdOWK/Dg53V7Ix9y3td3A==","signatures":[{"sig":"MEUCIFB1feRFc/TEUL6rDPIw4Qn5A0pSHJPXm9rH9qSoioQFAiEAkQGCc/yk1aX7esZ9s0QviIB9wJXlQOTBDYkN0Zdxy/U=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":52646,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBsETCRA9TVsSAnZWagAA/pcP/jcsQkGEyY0A5Sor547E\n3dF2bUROkFTic/XqpHf/PX/VNp2TQqzjhlybqrsTT4G8NxcJgaRBFMxR2AmY\nn6+ZcSUmXMNst7+TnqJUCbSbsSDGhGLEVYSBNhCV2lSGdX4sAMWSW6DE/Eyh\nft4k0l2yE/Cy++RXExmfMj9JgyGnU/GtWiGUkiEa+z1XgDAu4DHoH4QiXM0K\njMKZF9zpcid8uk+CjOV17dLHJ2PFI9WyAtlKv1BwsDcnOJiwSzje4lBdCQhF\n8xhRFwuZX1Do4fQgyCzCjsNFtds70uXwSvd415bmynHufLja9bVjVI0dO9Mm\nrmF+soRvI4j7djBzZFkc6Ta/L4WVbN3NghtSKSvDcXEl1h+uA8QSQFdGn2Cx\n4/1+l0GKaS9Vg17biZdnNNTAKInaGrmfqyJnHGTlFMSxkc5QgxuU3if0AINu\nBuypFG5LlCQ8Gd4wFNzespZOgWz2DjcrCxQVdr4/w73iCwCPM2QHEj/uM3sj\naT5w4PEMp2agsllIx5m4ltW+eTWTXnVVkinqvaGdez0z31wu4FUKwKbhiC1W\nfHC6N8UJDIEXusinp+aeO1bvHDY2KjpW54lWv3NTXtZ7dl5KQauIZLUhD4Rq\n//uzIGTFtPH8jkS4f0oQc/GfNahNcGhfzJvFgZUBPw/tItlUESzHoRuahxdh\n4KDo\r\n=Zyas\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"fc6a2bf931c448a2d6d24a802a3aef0ac135af5b","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-6883f82-1594278097863_1594278162321_0.9792820612653739","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-e644d81-1594284853228":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-e644d81-1594284853228","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-e644d81-1594284853228","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"46aa07fc3bc01621e8fd1cfc927ff91f93578cb6","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-e644d81-1594284853228.tgz","fileCount":8,"integrity":"sha512-29kD4zJOmZ2fVCNqK628otrJYiNroFVu5URjaSM7bD3jim2NTEMFW6uZyGOx4kH3uqeabkSC1L4oXi41V3AerA==","signatures":[{"sig":"MEYCIQCuOlFmQ/IEQEEY4rMCg4o73VW7pzkFVb4GyCiEYXsw2gIhAIFJ5K5D9m7997xncN/sRat/WGBIwWhSKW61B9R10t9J","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":54018,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBttsCRA9TVsSAnZWagAAd9QP/1A/Y4EUcUhX/Z5FIej4\nsCyl0y5Dc1erTVE8/K/080nGKYJdjwqJ7hsJN7xn9OvLTAP5rYwUtXk8zMTV\nqaELfv8xuQGqfIG6E+Vj3cSvNVHFo57o50XSNuFV4sNmyIaJWeTsrmixXmdA\nWbH2SEBawitnd4+SV33DDA0rLE46lR5jIPcvxTLW7MYNcdE2O1AVelH35aaJ\noyoXU0na0J74BvIxu0lD7XaTYyfwpnZGQuRq3715qW5cAUN0/p3UnfEel62I\n4HbnvH73b/hM0YKRk5ks6qvQOnLAAcBhdogly0zmhmPtWgWtg8Wf91i40Q3F\nzBqT1KXoM1csYH8dXi/cBXeVG44TPIidcm7dcgczGD3BbGO86pP/QhTP6cA+\noy+3KoYCYH+m7j4aPRHfGNUT+c4S2TPObaBwERAKnUtIWLvhs3BwmAj0mr41\nrmYrv0FfaqcOGCcJaC66EnAUaiiMdzEvasBNrck2KT4DT+zQ0CzcbW3GqzJx\njpKtJHTXNZ9QCBUtC4xg5esO5yq/Gar5fnKc6P5JBTBNThFoAmc5raT1ALvA\nqpnvVzxz0BwrLP1QRoY0gcbx2STnihIfGWuVO9Ba30K7Eoyj7YifJjrHS7ml\n/pRyE3LZjSEcMEGubPKOWf/0auCE50iAgC7vhqYgCNsIJ5ZddspoX80qkQOG\nKV7i\r\n=0FEa\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"5d4b18a03a0217fa9310cbe9e5a7ac3e6d7c8f75","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-e644d81-1594284853228_1594284907997_0.9910534870135808","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-ffd9f0d-1594818890654":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-ffd9f0d-1594818890654","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-ffd9f0d-1594818890654","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"777089a27f3a21a0dbd0eb4d8f3b81175feedc5d","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-ffd9f0d-1594818890654.tgz","fileCount":8,"integrity":"sha512-oqAoRcOjb5UQ1i8YLFk3kNmiYhxoCArTRNQgxvnfPVBWecx3L5joPIQrW+OxR+ZcUThdC6yRUyEClkFDkrFknw==","signatures":[{"sig":"MEUCIQCMXXqNsQT9GlRD+fksNbq5dPVJ5Th7zXg3Uy/HpWMsBAIgPgWUmSgvjVVCsgTr/xF23ST2gKW8G4Wi0f5w3A6+M3Y=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":54168,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfDwGTCRA9TVsSAnZWagAAPGIP/3s0ARRvXz/rhgDFajkF\n2pIz7ionU3e88SSjCgJ40pux4DOT4WaeDOpX0XNyDBLTboW5zyWGGba8Zkns\nqw229ncetmJlZuva0uGgK5QwT0iQzsvB3cqEzKpKUrYRBQIMwKq0s3e5212z\nLXmgEqPAzK5xSljz5jPRVcvp5Dmh2xRgmcQjOaoIrmAkemBD567rJAuuYTXF\noF/HTgj1Q7UPWh4qPXNlCaz5QcuLJ9Gzuv9eo+eMuH5t0zcbcRhyusHJITuo\nA/KjEvWzZLQWIo06njfvPloz6/XRWESelQCqch0cgI+KYAIni7sNkKfYQrlE\nxSioqFHRIWbugxAh4XoH4XngFbTR4mIs8mwGlCRoLpxSQ1xzZ9/AYTrD0Y7t\nEuGwpWGG6Ov7wnU/kd14m05NzKOHZ/4sJtGPJUOgxuvju7Tf0tPERVT/QjCF\nxY9xpkIkfJ2ZbyPKgU0/IuaczxRez7MXt4pc6cBuZ3Uq5B7+1raP0stxKKoV\nUiGqClVCAS5GqZVHwyxKF0fRsZBRTL/lZrqnf6jJ8EDh47mur7KJdVKr2LNX\nRpxfnX9/3bV0maZ8Uqshaq4Ixsz4qm7ktVDZwkTd1Z9BsXHKNgYcv8MdNjmE\n7vq+H1nWDd4Ir681kUE5Nct1Zx5esVC9b//ddL32fIjf46Vq/EGl6mAhudof\nJ/RA\r\n=hdC7\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"e323d226dec8040aceb94143416d44a43651e0ee","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-ffd9f0d-1594818890654_1594818962554_0.46827522735327487","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-afa3c0e-1594821096026":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-afa3c0e-1594821096026","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-afa3c0e-1594821096026","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"65350f26c8211bf65a751ba3dc5e544caedade14","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-afa3c0e-1594821096026.tgz","fileCount":8,"integrity":"sha512-nouHwgG0p5iJ4kOnPJ2PhXJ+AIb1QcAuuzcgt98O/zAUWgOoTVPpaAuc6dxg7wp7NhJqg00jJH/rtbZ6iI45yw==","signatures":[{"sig":"MEQCIAVIrfLvtlPNoJwuG1fqOAAyQQg92c7PHZnmQKpv4VYfAiA+xYbWgpy/ipAsV1orz4XGfNIHfamgGTr6J8inL2hTOQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":54016,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfDwodCRA9TVsSAnZWagAA/m0P/3FSK60fsh7TBjeLiHhj\n88KfvgTERaHg8t9RKtP0XipiJVIouFkdSLwkhxn//DoafEJKN5sKG4T/hAeU\n9SoGzrBKmQ45jx2QgVhP+eIpTHYmlBdb2bevxRuhLV75rYPAWJUH5yapEJR2\n40TvolL8qi9sMnl9aojt+9WHK7QxM7qsvYDJtEy3PhHcPJEbmewOApmDekIJ\nsPSikr0CwxDUMAxfBCynClDWrhEnAYdbZTxuA1Bag4Qm5r7+ubm1njWKuXwj\nG5ODXSO/JlIJyzYJflRMqfxoo79ED1mPCMy/lyykZYozSwpwOVgylYCctcBP\nEVFlVJOiC4U147tA1wSL8G8AN7ligQDg+gJau4Yc/Enxe6AzkupCYuPuH5y8\nV0CnnhwNTL3APt6EONNya9nB+4aOH8jqF6akifDkjoKkwe/yQXoEO92TBHFu\n6ssQmDTrvEgEFFOfpBRByC0s0005kHP6EgacKOpC58WlYL6TgVQQKTq8CrXZ\nOSL9rle8cKNo5IuBmYjg1T4Lj/SxzdZAwp8pAsNzwELihUM081Ypq94RDIeJ\nISJXJbRXXUlXFudTV8mN3wWIXOOSa83rQRh2ohiHQ6gPQUs+UG4/z5AdTtgF\nXm9gteOajG0ku99trLUqgszOf011jiPNATrLrqxQJ26JSgtUPucZc0Dt50mY\nVFKJ\r\n=L51j\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"067d1cb3791cba291f4bbc4c426f9009e1ff08ce","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-afa3c0e-1594821096026_1594821148968_0.3486274361878696","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-e4626ea-1595309115749":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-e4626ea-1595309115749","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-e4626ea-1595309115749","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c3abbe063e16cef0758a9bf5dbe8ec96b222aa52","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-e4626ea-1595309115749.tgz","fileCount":8,"integrity":"sha512-+meXPvaCiNkuw/kLWU6dM8omRgXPFJDZd8EIPWvNbWaJmLMnzNCu9+NZpgLRhotQb4YbAm3JdM0HrluHsW//Dg==","signatures":[{"sig":"MEYCIQCGxsSf6VCv43lkBjPLfWErqQmvy6XPC+ZOSceFGvVHUQIhAMJiPrNA5r2/o7SiT3eQUhZmdY/Aws5YxQOif+fCT1+L","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":38899,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfFnx2CRA9TVsSAnZWagAAEh8QAIOyTASHlvd937sb/Oq8\nEAN8SzHoJU5a+DNQLiKUAwORgZWi6EcJgwBxFeCuT0Bx5yAWsDLOR9wlkhZp\nhXj3Fph6luSTzFNJ4JwGzwkTofpLv3GhAluLZ8Ev6JoO9tKAzA+7l3we3xTn\nMOQn/2Hlolmx08omAlJnL7buoo2pz5aZE1xHt/0NCVrdPt5gzjhCu/iMP0La\nJODdUcApwjW+8s+ED7UfAWS8LF3IdKXf5vjGzbPkLSX9nvCu63gWZepFmGXk\nbU9BhU9vwUlCP/riVesCcrtUmalj2PtzO4JdKF15fGbUrazEPfuX+oZ5I40u\nNqCF8eYNMmVQRr2vR9j4Thchj+Y00MBIyJkgRkW4CZFMR8Ye9UrGXbGGRD8c\nYqqNgZHbmiuk0713PoyE7lvenTvTuZan0WacDbSRB61zUj+ZttxP8ipsijoJ\nzbw3g77W9GuaUSWTIQVAooIYvPh8Ip7RA9yO5RnVofhCcVofBJfk2PWT2w9e\n4B+Fg4AOcegLfaYPOuQ5sNWa7JBWWxe8Rohgv/jtJbZHfd5RjTn6ixz3exRe\nosgt269yEgi7eW9tUqbL68GWqWc0nhLNkNg4oFTTAnbLZbpXlVi8ZaxGAvVz\niPI3WZllrvNP362k+BJlDV9XHdQMjqUH+N29VeBLtTbXWhVrhf+yeQyRBx5j\n4+OD\r\n=s7q/\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"c44e1ac225a7ca912be5d49054c200da6d712066","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-e4626ea-1595309115749_1595309174504_0.248293238915285","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-2a89d67-1595401567705":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-2a89d67-1595401567705","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-2a89d67-1595401567705","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"51711b6e05e974a3a77e164f7f1f1333a3440fdf","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-2a89d67-1595401567705.tgz","fileCount":8,"integrity":"sha512-GFfn2ifIofX8f/PApMGgHMxWwLp3lWAAGe/tWnszL010mdHPf8BtUmHATF5wLxKlq7LXk8yQFkaMAWqMnddPSQ==","signatures":[{"sig":"MEUCIHGY3SKhAwZwoGlk62CFM/f1TLiSG6B0CV2T65A4uBngAiEApnSORIjgdbD5vVnqZoWDpaX7UKowipvcHbMMe+MXpyw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":54012,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfF+WZCRA9TVsSAnZWagAARPoQAKK+786rQwqqV6siPVol\nXHvhrqv8zUD1AbKflbd8LRBrRgNEqLJDxKXWMuAf+LAAjQOOmxKmCz8G6WIw\nEiI28RNm6WhRCzNg3zLJ47fc69OLhzK2rxC02e2NMb+ZA92bUs30pmgK4sPU\n6KxaB1+V9+qtm6GCCy25HAfthavc+13regPWL3Pivfr/OOYFprtP7736BuWk\nq6w+n4h7lbPy05lwm6WLRmisQM93Tay5Srrc9EknqQTGDXA58tLixcykryrH\nl78kbzKOYeA51qV4qw0+5F1D7shXqWafHt4thwWMkEdKefZ99UO7sdX3JkEe\nHzsrtdYs3gTUXHUOjMPWqssqdPnIJQpGxIjeLYDip0FmmGY7OLufyCY8QkFc\nyxdQ25fGZDsRt0ZiW1nVNKBACBAyZf5Nw11VEs6NMdSH43Y99av6T7JC40vF\nE50NJMOxujKc3g+ANia/2BW+VrxKopQTaZ6r+i403smYOy00bxDDXLku5DkC\nKeQ74cGyUkbp70rDNpZvcwq2JoCxicJWkMaPFk9bqDZr+Z2P19vRCLKtQitf\nWx30vUMYHTtLTKhTMibEKGI/8kvzQz14p3SEVpOucTZf0VkzBuMzMLYyStFY\nGdKzCVZtSC0nRcOfsKWShnofhWW2MagtS7XpVbBhkjCR4/NR61Up9uQcIkVN\n5FkB\r\n=fUxM\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ff04d2e841a320387204cbcf616eaca157c86335","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.0.0-canary-b793f98-1594019130179"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-2a89d67-1595401567705_1595401624808_0.40400966547033845","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-61380a0-1595776003510":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-61380a0-1595776003510","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-61380a0-1595776003510","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"448d0e5940545e53a8c7b6f4fbc99c34d4a9b356","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-61380a0-1595776003510.tgz","fileCount":8,"integrity":"sha512-CW4WQsHTgOKtGp1w/R5i5e4UkSkhdfQvyXLWWVkhK1LYPUVgaN5SQwzr1X7r8C2bVcH05+s1nxUIxqyzD6ZYQg==","signatures":[{"sig":"MEYCIQDRC2b8n0pcHjgjR0FKyUSetdCordScWzBDwoLOJOMrJAIhAKFlUlL57NnCfkwN4uCE1x9Vf2bQ68I7f4RGyebkbyNi","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":54887,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHZwyCRA9TVsSAnZWagAAvIQP/iFhk2gYhUfgw1ubdVDH\nI2Lps+6WfxFmESOm1MMEK3+QoQQEOA5Cr3t1fH3qQN+2uXUgL69XntKBwD8p\n50l7aU1R6MM50HgWcV177Vg4ZZ/vVNNAA8jviYO/1GQbAUzpu4AsoHk5r0xs\nZsliA2LknD0Q4FTPGlMJfOEkKAxtRAZuYdGNyekH4jCRd0brML/gcoHQxPOv\nVt0fSbWNig300+LsWoPE8eBlWGp/sCe6xCngnBfDLvLUgzzhpbQL2+h4ZSkH\nFbyOvrrn7+FkWHMpICioPP3TOfmbitGwrowAtV1Nq+E9Ns3sg7+1CdFq/aso\nHHsJEN++RGt10i7aWKfKffntLKaTJrWDRSh8iCZETEcpleRFzcLVR9WCv23s\nHkPYGe/qFY1/2kDKQ02FVxFQqa7ZbZzIGJz/NAIbKKivPgSbIo0v1fpSlTTB\ngvd3ESm5PwRstKLtpzVtIr8+eFbaWItG9x6D88/9+cABuKUn9KWdWgVZGxqt\nkzfZQOg0sL2gaJ0dtwVthcZHWFYLM7wTFykqoUtUdWZ3EMwoU1MJkKGKUxvW\nTa0JtEfrUr6GvNO6aYj1Ug8Q/0E4bQtuzMvstX/gNpciEzi1PqtzC/9qv3+L\n1+vzFedYj0F778yZUZ2Mmh7URZy1yX9BGSzv1KU4K4c0DxwJBki7U1Hv5g/n\nY+81\r\n=/hO/\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"39000e9e4f37595e95ce1c8cd20ff1fab4e22ab0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-61380a0-1595776003510_1595776050160_0.002571322659787656","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-9deb3d7-1595778576110":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-9deb3d7-1595778576110","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-9deb3d7-1595778576110","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"53da3a895fa82ab2bf5cd818fccf3f4cb9d426d1","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-9deb3d7-1595778576110.tgz","fileCount":8,"integrity":"sha512-0q1Yi/15wc7Azpj3Zuc65e6Et9W50n/Euun9nHnRTYPNBhErjyzk5WRL1GV77zGoLUcK+EdUDi7HdeWilYq6LQ==","signatures":[{"sig":"MEUCIF+tFvRF66xEnyImOgAhfhiNC7gM8DQ+P63eD3vDYsSeAiEAnK6wO+ielOHCRKsWMA+Tb4JEAu+pZczhrK7IQdDteNQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":54820,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHaZGCRA9TVsSAnZWagAA4hwP/1UEgH/lgeQzzxaGvfHE\n8q7TZhXxjMIaqluBFi3BG12306rzwP6y6dTlwgk5u8rX6urwmIc9A0DZhSwZ\nTZ8KQXs9plI3cWIzHHUL2NNwEqBopQwADeCJEpcSVAy+okAWVRP0LpliANWK\nGLgto5JKWVV30i1vb0HfWanwDvPL8IOAuUp0eiZj/04ChsehaGlrInCHXLjB\nr0/3r/wm2i4D5rru3Q3YLaKlx01qBkWybaoWMJWxkGSw8ImazDbjja0Hkwj7\nunRBjZHLI6sWJHFq3rn5z1ntUSZLKl1hY2UhV0qoNu7kjJlrgyiwW1+qWkKH\nkLkCOsPDaRdVtnenW5eGBLK5lbyoVpkva9OZEM/iQqf+5qy1ZgbMqKZHMtE7\nMg+0CikmJ/aDG16MDEpv88PRqyjEjR9WVeVaB2JWLpGGlNmWVuRAs0E8kGjL\nSORAGv252oJ6IY56/EmV1rKJ0/3hneNQzC5OICs4tnGyXmtQNkLqAD83yzB8\nUdgKAbjUlNnWvA6t7mppKRjnMyL/FxV5AI3tbHhbNzGV8U+oWStgRKHR+PSJ\ngkbVRRwa8WtxKAbiKoREiW72VjR40YmSQBGukDy5ylFmmVRHNOINflvpGsgv\nRuuzEFDBBuwsVE1o08GmfpLkICIK5qrmUauDiDTebG2eSIiiFrC3sEN/0V4j\njkiX\r\n=IY7i\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"cfeb3c38688ff0044cd5b1c93a57ab9f5cdf909a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-9deb3d7-1595778576110_1595778629429_0.1072462169099877","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-ba286b3-1595778842932":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-ba286b3-1595778842932","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-ba286b3-1595778842932","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"24e3692d682e4892ad21df3d25197efd521e6d98","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-ba286b3-1595778842932.tgz","fileCount":8,"integrity":"sha512-mtkikEJy96RkjHd22JvUsw4eFmN/JVHUSFTRqjvTGaHA0/jhm+XqpGWz5UYFuaLM6EJq8bD7YRDS8n70re/WjQ==","signatures":[{"sig":"MEYCIQCpjGtMVps8czxzpmXG5IPXvwNycLWB4h27+5ZN01U20QIhAMFDZ/hMr+taxKMhrteCbipbUQUeq2adKHm4WrEfVyTL","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":54843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHadSCRA9TVsSAnZWagAArgYP/jzMDOqs5e42X74MZRsv\ncZdwNw7O6R+FC+MMM8lB+HuLA7q9L+IvnwwhaY3GV5VkuXmevYzpT7FrKM2H\nFm3tR+JakbTHM21ugSfc9Zpx9L2gnDdnUHBSpcUFX2qiORbDrgT7fykaEOuF\nza69sgUUf1uVlhGBYHyIKq7YW45dyFdQpiqJf5LRoR2hVaFDS7TAfkveS1Qs\ntzwipClasEAOccQlhmjxywa2J3Q8RF/id0dtdYB+kQmAdAsEoft07mDfZWiR\nX5YrWXqc+ijrvO37S5ceBjLMuB8R25U8toedloMpAiAc04p10Mg49pCmTZXD\n+WjIWO9UvXuQGrmQLJPvXWuzeVadIIN3RtCEEaQbGtVLb6hAI14s7eHBKFzO\nYrRB06nH52v5O22koCKn2X8WU9sL257QmlyWO+Yc7yeG7X1zyUduq9Ti8AD8\nQsAh0GsjkB+zPIlPuzAbKMKa8lgwPgN6FEu14NjC2M3XYcjBuPkHmm0tSjLl\nkRvv6GgNoXw7n/pQoXoTMaAjLCtUCpjHD0an1Yvi+h5dk5CEa99ze4ZL6Q+E\nmhLoP1O7Kl/tGuKwa/fkS4HIBDFzV3jebYRp5wFf/uCIe3Snqc5qqREmuLQE\nuZ7omg43ck4xjXWWy9iIKXmAYe3GNaXH//XTLgBQJoQQQVuza8rJNWasMIUS\nbFdg\r\n=IKod\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"f39407e0591d82f4957389a900eeb2c69f4a9f0d","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","fp-ts":"^2.7.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-ba286b3-1595778842932_1595778897761_0.563818100105429","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-7aee527-1595779506745":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-7aee527-1595779506745","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-7aee527-1595779506745","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"d3fb984ab5117b9ec684dff5d8ebb7d4c67837b2","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-7aee527-1595779506745.tgz","fileCount":8,"integrity":"sha512-LI6TX2n5V0ExE0O1gQr9sCKIzh/+IX5YU6jFQXoxxmKzH8N8kSzTadY7GhgvhwhIPGXDiXGrr6qKiWLtjdVqgg==","signatures":[{"sig":"MEUCICigaEkDx7S3TVCMqcAfT/iPpE4ycPWmHc9lPpXGA/KsAiEA5wJCiiPlj9yqjqWJmeWTvKirm7ep2pDK3xPyj/VAoOw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":55131,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHankCRA9TVsSAnZWagAAMkIP/2vgYczmfElqCihasOY9\nVDyeQO0gwDIL4+yw+Wo/EP6UHE/Di04Fc6A7wZlKf+rEWfvikEpbVbpdYHHO\nLOql4CP+yrpxCgiJW4tcG4zp6hJlYSfwi7c3PYNKXB7e7Xd3S6ouH4QqfrY3\nZ/HauFNcEuyUDigc2ikQR0U8RKHhdv+QEfAzvYZz3/gFNNCVIwqaCq4uShpv\ncbyxYkOt+5UFZ0Qos/atlCXoPJ3nYOUi+vm0EJ9iasR7CXEJTYuuuXfesX0K\nlqTJkH2NsmMalb3uyjXTpQDpkq0Rds7UREnPVKsllYeF2whGZMT8WV+IocBL\ngY7TLPxgW9tcSCMFT/ceIgAeeXby1WDk4L1AX1kGnt2f9F/UQhMJfL1ykrVx\nwEQjb5qcRu8dMIprqRu8+zyzWsdvP4FqYo6KInzXWbw/1d3tfDPRI9FTMVKb\nta3eXCEijAYMK1JvLZGM91aJJ7ISgQnbsa7fODNsO5yXVD8VcyweV3hT7VdD\nIG4jRe6kZQr7qJA+CZY4ums45SZu5Y9bA+yEoNhErUP4AzpnudsoDMUyUaiH\n7hU2ipC67rhlfozkx4CUsUBosC0I0gyjzzC3ideXTdq1UayYKcIAwVbAHWAt\nwRxUJ0a8kKiFKI5Laz2qeiqLxl7FD07J1U/swl2FCpwEtsNtUwZmtpIaEO1h\nuJ3d\r\n=/vs5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"819803e68b2249b8739c3215d284b69dc36809f9","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","fp-ts":"^2.7.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-7aee527-1595779506745_1595779556248_0.9110897180548851","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-7ebb861-1595779992746":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-7ebb861-1595779992746","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-7ebb861-1595779992746","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"84af2ad85298496594416d9911a58c80bfa97a48","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-7ebb861-1595779992746.tgz","fileCount":8,"integrity":"sha512-68A98cocGwk18DDzz9gVJSxgz0dGdbOEW+h2DQkxlF0/ixtLNcCCrGahGeZrq+IR55+17zA8moZnEHIO7mEjjA==","signatures":[{"sig":"MEUCIQCCvvyE5H2p7ijJNC91+dgWd+0vjNutYT+i3sBSEUaczAIgZvicroethXmuefLXR89tUTrFKI8TQ8c+Wxt7ziSso4E=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":55131,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHavTCRA9TVsSAnZWagAAZzcP/R2Ryz3my8Of5Ueo5h+F\n6tGKJeh0txpW244AWXbBeOwT/Uf8nDzhpRkvicGTAt/EOKbjywc858+I2Yyn\nreitY6VgA3uOa0pseXlVwlPD9OAQV72k7af7ephcbwCU7SlxpkXL98IUtJ4t\nnYBquZKcEPeYyEs9wOb8eyM6Gnh4ToNiZ3/RSWlCcv7o6BvDFByh3GTuii7R\nNWnJ79hD8N5JNdIl+xROvl2teA3IIgk5eBF+OzlajagsqeHHgqgpCf0U44jm\n1sTbKQgamxpkP4EmdZUV/yuHAUBkfab2M+Eq4/kLpYGAXcj1adLB7EGoF520\nWsDDEFGntlRJa6OxV67Gxpsm/VwjfQCTTuAcAgaf2wdFy20OVCQnofXpveJQ\nUlJVoUAAOu9XriCZCd8cKVY2P+h89naQnyD+IXGlaVmc/8328Uiehz36cm/U\nxJJ4rc38ezO7PgEOwC6MtnSBpVSMMXD8bBQScRTGp3gcmCrXyxnz/eF/bi0+\nUIiI63A/rd+iQyG8BGySXxb9P4Lor8Zy+qlAErLvmSJFpbX1WWlK4uSvpbDK\n4vYO3n3pSVk4/KG2QfTdgcTrFl1HESPqRptqLopPzSchuS5qI2YtKc9cCfCW\nHTigTXCAJbzVG5RCZGenEY8E57UpTlfCifY8eqLhGawSIJRBhYd6g9irbCm5\no4TO\r\n=frns\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"cf054fc7b4a92664643cd83f945966fe8904340c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.4","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.21.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","fp-ts":"^2.7.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-7ebb861-1595779992746_1595780051063_0.35541220209692037","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-a1b16a6-1597312139040":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-a1b16a6-1597312139040","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-a1b16a6-1597312139040","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f80e633ec5714bb229176fba904a9ef216f4e815","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-a1b16a6-1597312139040.tgz","fileCount":8,"integrity":"sha512-8JBWbRMlyU6ka/saVbqpUVKlwnNL0rUj86qlCO99f7VakU7armk1ovInuDwSocUY1MkVYaxnpkC9zjxxmIuFxQ==","signatures":[{"sig":"MEUCIQD5Iy+wC4g74DHPI8WS++VkTlkUKmxp4I1+K5vAFBzweAIgG1NpFyPeAyS5DPN3P2tML5RFoi28Hkyc4xO4NcIl3mo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":55139,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNQy5CRA9TVsSAnZWagAAyLUP/i8ItTVk5vkROi17N973\nqXZFmiGKe0VSaqekwftCBFPJpvuJ3m0tMvabwCQKgqDxGl4z1uLes3WnB2ex\nzy4+ihSKJusqyWGkrD1V9gGOBZdTBmsvTWT+C3XwXK6qfDGgGNJ5SQegnnWb\nZWVCrkjYhUZ/1ECZRAPAwmqCyJ5xA//jcWv9kvfLLwGP6i+eBegDU5kYQRqv\ntwiap5ysJ2luFqLnLeiWNdtvxglnh5Y2nGAz5RSsfDFDKIelVVSygmAs7WYg\nqBVYwkK5B/s/ZXLrvAbjHU6B7zutvqFDoOtnOeS4HRE1urtc8UObfuo+ynNF\n+xcUGAqtFpbgENHGTj9YJl1Zgw+iPgnIWsSKfO1REohxriGD1/EwgbKsL9H+\nflb9RgACxMaWF0Fw7A78NYh5yIqSKqbno5LuWoQNRQppgTECrbaZfGkcqtkt\nqVgc/QanVSyi9/PJpJsmc7H4DYPMA0hYYrhrbbq6r+JucRjruDzuiYqYsHdb\nPhuxYOQ59J+yGN0tMYgqgsAq4ODv7LQglsbdHTjS0frlUHvqu8SkWMLs2k2X\nFi/sj7+hponra78F5GSZrDfR7/VWSvMcu3C9d4SJNUJB+Da1A0Oc7DaRkAYH\nLYg8UP/SQhlE1UGgsBx6mYjbs68jhB+hICfbe3M7droPm/Axai/hFCFuJk4g\nFya9\r\n=1u/2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"5fb19463b8d1722eb20b7391f8da80a71b0b2f9f","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.6","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.22.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","fp-ts":"^2.7.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-a1b16a6-1597312139040_1597312184939_0.3124200505352981","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-555c0d1-1597312766029":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-555c0d1-1597312766029","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-555c0d1-1597312766029","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"35ebdc623d6c1704ea1c79088e07b76c2705945b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-555c0d1-1597312766029.tgz","fileCount":8,"integrity":"sha512-y7e4cV6xLEQ2LHKqdztr+1Ue3ZagxIy1fXEB5i+kOjjW+zDSSe/aJoa9mvHwRZt5CZU8gdnnw9mVpTW5/3qMFg==","signatures":[{"sig":"MEUCIQDHuGbS29P6yox4Fqgr8iQQD729fL8861rwdNI3Xgui1wIgOPOFSooPPWwJXftvhFLufwmXOS1mGP8F7RJsUBtz3qk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":55553,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNQ8yCRA9TVsSAnZWagAAzrcP/0uKqGvbgDz3XHPXkx8p\nQX/iQobzRRMfhKkW62e+6LTrGazLZU0Rq/7vI56SQ3MwTEQJ3dgqEJQBC/fB\nWJ+SGVIOB5aM01XEwv7vvoygRZ5n8+vKAXkw9HDKwp3SBFE5+WAkTpOuqeCb\nNsUWWfUbL7HdHLcagRlczXeJM99U3zd2AfPTRHGy5GQtY9Mdwscq/uQ2bVUY\nrD0xpf+Bbg2khUdrhaGQDcDtYD39YM8llqkx6+G3wV5j/adPtgw1hXoqUlZ5\nuMznyFqiNSfCMIjGrUAxDqfm8hjoMRE/Vx16bwVYV3dq1/REoNSvWo1cH8N8\nSDaJD5pEZv5SJdpm7HfjpG+7zrEtZQ7aYvrZpBW6194yARflDXITMnwz860P\ny/oiFgMMAnPLc0IxP7NiaRK662blUkKYzFD43uwal7I/Zl7XhAha1jqtLVtn\n0vz7klS54YKd4+g7BAcjGUmBFayQGZgA7GvDU2+psLS8jKDQIWshrthn1gnU\n4Sb56R/pOU7M2g7N88KBJMUQpqKdcFcEjZXklMQQo5YwvYVER2wsIc1W+viS\nuANf1LDmZc5ET7in3aSRCosBDdVDghO9pE4xGlstH4wqnu0nq4V6/tdrUjr1\nLrbuP/tBJf4823xJ4IMDxQ3d/EAIYxOc+9gsbB66YdCPgpwe8s5Dqv60PPw8\ns/13\r\n=OttG\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"92c7c79d3a002c666592d5a55028e89a9ff7b50a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.6","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.22.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","fp-ts":"^2.7.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-555c0d1-1597312766029_1597312817675_0.3084660977516105","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-20912ef-1597312991148":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-20912ef-1597312991148","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-20912ef-1597312991148","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c16a99882cd819f6c4bce00dd131ee7918d6a3c7","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-20912ef-1597312991148.tgz","fileCount":8,"integrity":"sha512-sRtUu289BAh6JJRx5h2rhtXwOWFsXR6QxAQzbNgL9ezE+uMucSzVv/OecolJWQ5exEt2GgForfcOT8dPmd8AAg==","signatures":[{"sig":"MEYCIQDxR67lvPxIDs0ea/LdcLCXevh/AnK3BgKPPhI6DtP0/AIhAIj22KIHG49/5qb8Tk4m8WTKO9pGendi9+BDgRLvRYYl","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":55375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNRAcCRA9TVsSAnZWagAAj2wP/2ZXqrrlGkepLs/rd10d\nC58nrrvUskl1cNykl9/3sAxxBqA5FYgiA5RKZl3bX28+GimidQNTKdo7EC8L\nBDyrz6UgVQ2Zu3vB0Ln0ZrD6LF1PaM7rkJjoHM8FnMl4MSPeCmVaroxCLAEp\n5mVJghhsulpxeYF0DkM2zjXjHJcGmcJ15JO9+63rvDL2P9lqQ0dbM7wWJuLD\neFH3O5r61F+WXYZ6y9quRqolDnQYBbwaBylAUT/BOvQgNvHNonKno3bkuHkz\nGJBcOw6X+whGfxJztWazXS386nx612XqUdYcVeiZgRQ8bqaF3d4v2tVGf3Gi\nHeMoUPDu3mHe3nY01OGagyFwWZEjtlJXorE6+Xzpp2S57PtSfJYbWuW8rHhd\nDrRDI3hvUdp3sKG/ByoLy5z5syZu5RRR6ggRlOQc42UzZcLjxEqhH794t27M\nGTAKEo/Vz/32GJg06KpBpEZ+zvbUhvAGBOaYpvUWTGaZqrWFzqkxyOfH05H4\nLHMD7ZrE5N4OHLdsyTANqnMMP/I92NfyfkbqH0a1JvqZLoccMeHvQzyez+eJ\nw/sbMvBigx/fFf3q2JMjdqytBc7QpGAe9JNTKUDatEDYkoawizg5GNZpDREq\n2/hLcyR4tqn0h9hTI4RIR2eytWFsAbu2CS9iOaBtKVQDadGICdSagsn71pLd\nCW7O\r\n=/fZK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9f9210d25148eaee447c3b7ffdb1eb43b4a83bc1","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.6","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.22.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","fp-ts":"^2.7.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-20912ef-1597312991148_1597313051569_0.8748963628709931","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-a54dd17-1597313977707":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-a54dd17-1597313977707","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-a54dd17-1597313977707","maintainers":[{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"715e4d9b0c76bb43e98fd992da3c49921b09f12c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-a54dd17-1597313977707.tgz","fileCount":8,"integrity":"sha512-9LWQC13wuwG2kgqOZgET7u2e446eQLl+CtZfVfYlAqhDglatccvrY0LgZex3tC6fTQIwHgNQfex2RgkKhiJ4RQ==","signatures":[{"sig":"MEUCIC+DIPDOo7swX6ebnZGDaC8vzfiSnQU1LwivXltAlcQiAiEAxK3uKi0R5WLdgdjdk0yhIaXAif2DAIkYadQZBe4NcHw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":55313,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNRPqCRA9TVsSAnZWagAA52MP/2daSIUh5TNx6Mvzfj9P\nintGdujr8gbNb45DTripsCDVQhLzbpLRQs0JLOJmqkyfhKxy7y3UbEMsYFWs\nhYfXWKYmADWgpM9fEcgAS/N/8D8eLGP2aGF4R7WXCU9ngTkZdEG1b3d0H8gU\ngPjN5Fg8QvP0PXzILMfHv9HvnmNqR6/HiU8Dd220rXj1Z5oEtGO7cjMUE5D8\n8P98LN45AqOCo1RU1EgJmw7z92e1dUlDaM8LuCk19pJxAigp4p7MOlgQNCMN\nSXUY8nqhu/OowC+r06TMMfLg/Tl5T23YNoQnTXRnO9PgUyx02ciaT1+EmQZp\n7y/+opAs7XvVGzXMbGEUhBpH7h5ZdZ8YAf4tjNX04PnGa6XsT54IRrcAbmco\ndTChb2wFF629f2+8XenxhgPg1sT1Ad1Q3jyCMzfXueCC5kAZD/6zu71DuBvt\nzAtn8t5OezZi6Wv53PxcEajslPVmSy1CN93Z+RNZQ9Llw+bdBmv35osFbOiq\n4ERQlFWbwWhKmDAPickaX8Q82d2Z7QmV84W6P1E6fTpexIlpnhKe9I7hWcC1\n/fZRght80KZPDJiZcYHGgCJ2K9MpoV/tMOM4q48lQlvv+NlvH6rPvKC9MZ8t\ntM+FGg/PVTGznbkjxo3u3KOjoruR9arbxiimsvaNU0DS5q0rsQfU8rjGg+mz\n+F0q\r\n=AA/m\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bb0fd902cd5f93e621fd5712a98359b3868beabd","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.6","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.22.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","fp-ts":"^2.7.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-a54dd17-1597313977707_1597314025708_0.40535437610313263","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-e5e6a73-1606260801933":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-e5e6a73-1606260801933","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-e5e6a73-1606260801933","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"52ca3ef17848fcced7cf39334506b6be8a329ed5","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-e5e6a73-1606260801933.tgz","fileCount":8,"integrity":"sha512-x2zYLqUWp9Juxsfs8LgAW2mhWGJIDKMwT9SNC0B/IJ1cLtM2mHJvrtpOtooZypDGzCLyOAnBM8x2lndVlehc/w==","signatures":[{"sig":"MEYCIQC7VsTG2xFqGvB5G3E/HdmGxV9zLNW7M2ZhqNTmYnjMgQIhAMpQKtGVdgdiB0HIOuKPaTj5D9HaYP5CSodJy9TBCd+w","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":38899,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvZh3CRA9TVsSAnZWagAAPrcP/A/YX6RYVXyLvUzXC4Kr\ngJlmycLYuuk5LycFjut2GNTGyxWkgPsSiSLqfPO91pJSFEXb1cMRk3SIDowW\ngqgIejWi2jHShmETqk2si1mny4J2/2M3J2KNFLRwd70IlBz1GjOpbrTxDjbc\nTbRyrz8jLMmBIL3DlavGkTV1TcMU/k0iKCYwwekTQmipR5hzpImysii2edX1\nCUYdTh4o8JMBibzGfLouNoHNRKT3Mv2bKQ1fqtMyuRilwsYnRtpa6jdC0P96\nbSf6HiUVSOdBWh1/uGA2g1bp6sJrDFi7jTBRseSsKXUyRAj2ridJAVfZFZ0c\nL6VZQvXHy86Yx0HVEsHiFa2dSMCBb9VHGxn7MJfMQnrHa6YZCcaGYfp6fTKn\n15uOA7xHeSlqUfQbc+SEufNPhcPfXnGOB/NEZlOAU8Y5DT3BpDROMWp9liCe\nIdoM8YRogK5qpkraoBC+GYh+pYACNOF/cUhGaJWQypFS0bqebv+I/7oM0DrD\n3Us5M3Rm4eaLsIAmq65SGQSZn0C+ITJ2J1rtN1FBU8jCE7HPrLVnUl6rSX9t\ngosZ+V/TXmBvEbbggj6u5Ob/Z67varPTp3ssGvmDWxjd++KfwXOLUwxJFtPe\nuCeB1m0zFDKILp1mnM6uFEnZDNALoV/qElNJenZykFMg3Rq0tPR4L2E3TJvq\nTc7g\r\n=CtkK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"e2527c99ecde2208062d64de254fda73598f3f1e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-e5e6a73-1606260801933_1606260854545_0.3528311696256057","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-8570e70-1606292401028":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-8570e70-1606292401028","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-8570e70-1606292401028","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f3b83365b222b43077d5b28f3b04218cbb2741d8","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-8570e70-1606292401028.tgz","fileCount":8,"integrity":"sha512-R/JbYQ8p5UYTmzleJwinDIyQALep99eZpI0cq63bfEk5tljImdf0/69/jA/AbBeHmXcvpmlHoPRXDvBgNIg6ww==","signatures":[{"sig":"MEYCIQC3cJjn2/PaAT72rnFhpQ14LevkW4qN45YymUhD0vy4ZwIhAMWNy0iooKxLXYR97UtDzwuVgfbD6LMvQAytSI+LcKud","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":38899,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvhPkCRA9TVsSAnZWagAAtFIQAJ/Bkh96s0kiWK40xu+m\nv+8Zci8o23E5b521rXCKvexebn9yHKwDF4wOHhDGH7MM4ecwQSHy6gE13++4\nm33N/o9o7MW94lHPFHZ0AXN0dD0TJqbp1H/l579sPejdMlmLzoP8HrmlmX7r\ncSQey2X3JxJAK2LDUF/8R3Ab2orv1P8bsYZ+mzjhCOex3zLJdIbpYluNkCi1\neqPCOJb6fe1JsRr22ezHhqYsj2xk9zKSgr7QKBOYVtXDBcQvSSRmPw5G2x7Z\nuX5cN3gvxXawT+EOk6cS7yA13WfeAJuQ+e6+KrC76kcfh8/M9cd0vwvV54Aa\npImU5tO+Y+/+riAhPXHw7nSVhuJTUYLJhJ+0+OJvtysKGoKqF8LF5VzxT6IM\n4QE9DEGulxuYNiUfr7R/qEbslmVpbGA0FvWccmCHgus5lxIgnofvlfUT9gkG\nC8XV5izCq+7M5KzEWb8p9oBbk6KAIMgsXfvQLNk3YDVLlpAvMlWDoz3AqvhR\ngAiWuRi7Q7lQ+ESFxcIhs/MBz4lgPrd5lN3P+Cg99v0kjxORRfBVx5m8vz+N\nW0DFqxE9xgfl7pbrfw7m2Dd9U7DdY8s/G6yEGiNBNE9hfK5WO2Ew+5B2c2/g\nztu+DO2S6kLGPP2XI7G646DZ7HEkenVJKbAn3Oh4O6jg1J3IlsWyXtEurS+a\nVCmI\r\n=2B9h\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Usage\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"078abd623e0ac0d4e0ede6bf7ac1a5b48192aec4","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.2.0","@iadvize-oss/foldable-helpers":"^1.0.5"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.11.0","jest":"^26.0.1","tslib":"^2.0.0","eslint":"^6.8.0","rollup":"^2.17.1","ts-jest":"^26.1.0","typedoc":"^0.17.7","typescript":"^3.9.5","@types/jest":"^26.0.0","rollup-plugin-terser":"^6.1.0","@rollup/plugin-commonjs":"^13.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.27.1","@iadvize-oss/eslint-config":"^1.1.3","@iadvize-oss/eslint-config-jest":"0.0.5"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-8570e70-1606292401028_1606292451578_0.9716774683021698","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-9f761ed-1606485464437":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-9f761ed-1606485464437","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-9f761ed-1606485464437","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c2c3e9cf8711c0009e41af813c2f694bd671f33c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-9f761ed-1606485464437.tgz","fileCount":8,"integrity":"sha512-EBHi2poFczOpHxdlk6ZZ1J971f4AsXMenrGcUeIAVI96bXofqYTVKhDljhXhBlm7Bwuz9y9W8Sz+YK3MVj+PoA==","signatures":[{"sig":"MEYCIQCDtpUf7+pOu5oG0tzeOA4yPQ0+zrX0usnZJJ47cAp+mwIhAJk6P1l8QnJ343+8FtVJ5huRyxDW13ek5v3dFJlBpvU4","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59906,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfwQYNCRA9TVsSAnZWagAACAwP/A3yY7lKY79aeEwVs4S1\nKXTkYBUS+GjzHfTpwnizKn823Kt/FT/WWGypcmFhCqbeBCUu0OHcQszLy5MB\n4u4W605BtCbE0oGtoeSBqKN/USawNJit6luGBvEHmaTFXGuwc8fo9v2AyVT/\n6PCEiiFwZRfncdPv3Z7QjRpjSFLuXSdXu+q2Z6errfI0d9VKEhkxuaMt7Sa2\nQjbeqB93QFpZH8G2VwZ+wXRHJinMiMvoAEmyfTVCl8k1RLiBlv8CyRcUFgJx\njvTHU6nMz23nNoDETzkHynaOvX0PcEuOnvA4OBFvPQMumMTBbV5zkK5e19EY\nSSj6LaDhej+1bx2ynURAYpYPmyDeefAeJqiK0mLnMw3vjRL7xW8662GiY8AK\nuFrMPgwqhzxAziudEMI6K1eQWRJbRUaqNsl86t+2XChZjwvxuXqGg+h+ANk+\n3TASUw0VwJyMN/f70rbFbrnqGeIPGRqaoiqvsQeE1chOLMALTSllpOSXNScZ\n4ffuP8TWcU08DzhSE90mrWtJFn9gGtPSkdurZ3CeNnVPl6+bC/7PfIepo3bO\nxVdRMPwwSbLwVbsMDzvurxP3t2IFpeE22pEYQ/l7/A+ByzDCV0zna4Fag6kn\nHahoqG4kyPlLAUDEhvYHTDbEjammne6MDCg48MlnHZm04fxh94/qsjictIIU\nJYmL\r\n=DuiZ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nOur `MessageAPI` was really helpfull but, what if we need to show any Message\ncan be `Pending` or `Sent`? This is what is called \"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations you can model your entities with a table, like below, while\nstill using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"044c7645c453c7f8429c6cf429027a4df0ba5e39","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","fp-ts":"^2.9.0","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-9f761ed-1606485464437_1606485517180_0.9699887578373267","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-12e7c42-1606486142836":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-12e7c42-1606486142836","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-12e7c42-1606486142836","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"3aeb945cf48929e4c0d0dc1ee032e51a2adec556","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-12e7c42-1606486142836.tgz","fileCount":8,"integrity":"sha512-JLqF7kyWGyy8p5XaKWpLIrFgJ5segPHx6yfwmmzFEu2LEXIpTBwI5ZLyuIJ/eDbcriguDu3uE0aitwIpLUPXlg==","signatures":[{"sig":"MEUCIEcOKMrr7xLRYcUi4ZI/yxviPU88/r4lOJ17iUGgzTV4AiEAqlMTiwqMfTUs0o7q2fVi2gNlV7xLiRW1QWBPnZS6WMo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59906,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfwQiwCRA9TVsSAnZWagAA/ZkQAJwDLB1BGKNRZAZv6Bto\nVGw0C76EbEXsXDBn2BgoFkDK4zDGP1DKBy4t6s7zJI6gd/xP27SmezuEwPEi\nBI7BM/ACXmvSBnfpOyKNhZ0MLYX8fU28N+WCuq02xWRWoyuNQU/0+ApjEvOb\nMJ+C4zgi8QLZxrPPxPvmsA+zi/k0A0lpt8uG/tmBaNWJB5HrInuEPKUKgrrs\n0iRMneVN0MAdkdT7nuKthBCGUVwd4xgUquJdq6eE8IDt8Yi7armEMqrigDTg\nLNaYG24x8si6XxfbAzdcyseBn8F+PePkHuyB3oVhaB1Zz/Hg7ujzUaykS63e\nnvK5JsjNG0V9CA6Wi3SYlpIAxq2OwY+uCoKzIVtUaswpEvCXxqjXKF2WQrfe\ndnZGCDGxMvx+Xr3jAhCOLWtvcrC41g6UgBZJsGa1/2wBPnnK6MUkgk2tH8Fa\nidyXHvZ/Gv32Wnz2hkWNXzOSG4LZvzMkRh9meeUyD8uKrrDMLNTupI/KS5HO\nvyGOER/HAw+fUDtetv+jzGDStg1cIdSSfT8xMsXgJHxDC+gUUYl0jgPSG0k9\nNdCtj6Ph3Px9r/0bS7a6Gyk1iuRdrihu/Xi097g4v0mIG+FhHXECFxTLdBdN\n+fE3TnZv+2CJ+ZiRTuLy7iwW7WPERLZ5dWQZrNunEFDvV+3iBLMMmeSStR9y\nbW6T\r\n=0HGy\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nOur `MessageAPI` was really helpfull but, what if we need to show any Message\ncan be `Pending` or `Sent`? This is what is called \"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations you can model your entities with a table, like below, while\nstill using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"c60839a4bf0a5c6b3b95745aa09f48921c33b8de","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","fp-ts":"^2.9.0","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-12e7c42-1606486142836_1606486192466_0.24987837649807942","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-a4577e4-1606486368796":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-a4577e4-1606486368796","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-a4577e4-1606486368796","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8c13bb9d5fc46960f1d49ac7548705a25a468d08","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-a4577e4-1606486368796.tgz","fileCount":8,"integrity":"sha512-FQwkisdMwMfMcqxZ0jAJI5Y69DI8JH/vbtkyiPTOl5QGncbUKeu2ukqlIbiZGU1t+ZrUWsLct07pnuVWtV5A1w==","signatures":[{"sig":"MEYCIQDFE8Yg4WnVV/bxiP//eXyJ2ogw963LpXHVHMSX/gwFsgIhAKvV0XHa+SqQtQWnH5iEpsWvOX4C32Mr3k2FkNLxa+wW","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59858,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfwQmbCRA9TVsSAnZWagAAsacQAJXa5RDx89gqJaPOVvhz\niSZbz6WpoejTK52HBXyx4xVDqLqAuZ2myc4UYNqqulhiIhOxk0524OKftidl\n7c0d2u0Zxkm6rI1MGBSZyvxsjcb1Zyf9Lm7W06dDf1vepHNhpxbCuN7C8UeR\nHTjpiLLQw2pBinng+TfegU+VDDch7DX639ckV1UJXZeFX91RMFwRFapqkNjl\nc3H40vDx0riLzeFLS3puTOwxneQ2HGEZaL2Ba2j+E/zCPGDVWRkwc2gtqfHa\n3pWc4zG9V0dwWtVsJFOkQowxiEAumczXc2tjKJVV4E+f5xjY0bAXRhp17nKL\n/eXyjxj5t9aiv4mPo8Zy7IE3cX9X4YyGtt/sEXj0zEnMVXW6WqmOzcV29sto\nHa5w03/+3nfnFzla719Ch4M/AsBnHUzU4ixJx5dWQGK1yd2w68yD4gsuQBnb\nSm1mTmM9G5UHDmx7k9jszIyJ31798Gs4RlE0ap5+t9cRNAkSlviEm2gahy6O\nClsrNt1Owp4mkRsAxzl4dCMNLoWDXL+gfCRfhe+1z19JrQtG4DUwXjp/CICr\nH3oraZxdlByW42mIAyvO/Ur7om1dAeSzuNveGoRDjaODKt8o5+TX5AZDtydW\nShB+36/ctZWho2mQuGokaPT1Et71/Zy5+89CUUS5f/8ZLbyUU+vzgeNNn23l\n9lRE\r\n=oJxD\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if any Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations you can model your entities with a table, like below, while\nstill using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"c7a05fec25c7d8c1aa27f70e9ab11d55a986379e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","fp-ts":"^2.9.0","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-a4577e4-1606486368796_1606486427106_0.4775764759460033","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-d41fe89-1606495585351":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-d41fe89-1606495585351","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-d41fe89-1606495585351","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"12131d34bb5e80aa60dd37a576674609e0193979","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-d41fe89-1606495585351.tgz","fileCount":8,"integrity":"sha512-Bi7vx9zwzcYMHie08Ub134feO1dvMIIO/ho9zS5qB8Dq3aI5SVY1FoHtiYZ4zeFxKdD3aKfKg50X8Uo12knsPw==","signatures":[{"sig":"MEUCIHXKBXgDCjL1TMN+8T5PKtlVjQd6zET89TrtdvoiZUKiAiEA+in3QOn0VaQyjrWDf4+0L7gN66omr31zRR0HfPmc94s=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59858,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfwS2SCRA9TVsSAnZWagAAzZwP+QF8iX90OaM3r8W4nMoE\nfI5x1LJn/G1t5K/Xb1MhtsGfhb/TIXBQDvce+6Dg2qF3Jo3JW3pO62lo/IEU\ntAoahyroRfDd/CthJ4+v7KcyTEjDNBNfkRAK+3IOdPTmd2q+Xqx/eAiH1KAf\nPtSog5GhlMx0fI1GphGZ3DDIoF6sC/hV88v9Xeyl75Y6y9gRm4nw84oqFwQ8\n5zQNghIgflefxEwowJ+L3oAijw4RVbVoGfhDlsW1/i201dVviznMaNfrt5A/\n7/M0z1793j+GXInC3Ei3Ju0nsLBEsXXOroCawkiXx1FXJuxj38lQNnZV/sL3\neWhnNIez8wNcPCugV5WVF8ODr3dnkgx9KFJTrOE3Es3HRyTQC+BDO8Bso4SH\nKPvVCaHs1tvddSA985EMrXVth5MqV0mCcPG8eRHM4QyQBqYaDuoULQ/wNn7x\nSt7OMW+Qk4jWhLvmpm+Nnou/0KK9YqJM1GIAqndosKUkoh1Tn+uSobsibVF8\ncb3GHcknux1OGmF1HYauJbiv0C+uTPlshOebsqpiq4GFMXeqffkTpAJkKLHD\nvogdohFl8hD/d72qpvjh7OxOkVgakrgXZnJApU4YUQ9bWQwXp/MBxXRzGL/W\nVDWxC2Y0P6fxUthy6zW/czD+ZazbVk8/+vO0tU1Y/b8SCJ4uAWDDXSd42QEY\n4YYj\r\n=/iLL\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if any Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations you can model your entities with a table, like below, while\nstill using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0f81cda7629415d9f6edfcae168deefba79be923","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","fp-ts":"^2.9.0","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-d41fe89-1606495585351_1606495633940_0.7673496321902671","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-92be957-1606731001013":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-92be957-1606731001013","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-92be957-1606731001013","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c55ec2018113cccc9ecac041a51af2c71e669bcf","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-92be957-1606731001013.tgz","fileCount":8,"integrity":"sha512-EM44GKPKnQesOWdQPd/tNV2mWmp8Hqq79QOQ3lHd4oPuj1rtI1NgbbB2d0iCRWfVoNj1e8rKuaTMM0enwUkjuQ==","signatures":[{"sig":"MEUCIQDUpC81p8pElRYrbS3psPs1nnmBK0wy7Xi7TSDx7Zi1GgIgchwzAsYzu3HfuqYc6Aur/V2osMnfEUaSj363BFubKBI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59833,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfxMVCCRA9TVsSAnZWagAA73kP/08PDWBNTAmoc2JAR6nY\nossowSa4DcEuxzlCVuYu4SFRMXa7M8ZrWLxnae5+OmXrBR8zBZJBt5hahlQL\ndmuBeMP0T6kA47ykHVTlM89TaMJWS3Rjqyjzt9hzb/8C7CWWM5P82nZoSHUz\nYoXIbcfKOXJ6Uh3hZdXRh2m68xg16B3fZ3STvNim0oyWUbseclIVgCcV2V5Y\nrhB3637v3yyY1p3MuQyTIHtIeuiiStEr2cQH5wrfm6AspMy2w86N0JaaUSQF\nlXtIQRm6iSkrVfmFlwK0ZQl8B7l3yz5gtnDj87XSdiJ7y/n9I7g3UxxxnfrO\nsOCq+rQK+NDUO432ymkF/4ymdY7dIZmwMOaAk9BH1uVAi8FOdFWsQrfowB9J\n4oMVJVMgZgl/FKHSnOu/rZ/Kd//L1kDUo8Cxvgo05chXjP0Sb263LyqAeIBl\nQk+v2/CW8dE3sIQfGHhINtJboIZKM3wXvrPcDNBSt6YULCl63Es9+YQDPVsO\nnfjGBPxY4mbOglZw568py8+9x+hOXSKeMIJsIoUExwgm3+4DValxtf7tPP6w\ntd9kspzqZ5rTU1K6QDtRwTep5jkdoF29UHydW8jF8P6atGlBh5/nuWjuaC+p\nQ1v86WaCsItdeIm3JRjU+BTZDs7Pgdh/DBlM3p2i507dTKSEm9jqbZYFU5a7\npYSZ\r\n=GIzb\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations you can model your entities with a table, like below, while\nstill using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"62d47ed17b89b60e75f426cde2de2bb066237e58","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-92be957-1606731001013_1606731074099_0.39442199456322435","host":"s3://npm-registry-packages"}},"0.0.1-beta.0-canary-9cd51e3-1606731377063":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.0-canary-9cd51e3-1606731377063","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.0-canary-9cd51e3-1606731377063","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a4f14083fe25f2c4d11752aab1bc5da61b9a0af6","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.0-canary-9cd51e3-1606731377063.tgz","fileCount":8,"integrity":"sha512-x80XBvqPoGra83sH7NxOqGICesSXfnbLxi4KqZcGGGpJ5Ao1lOoDYkkn3naEcqsXnf8tvQ1VJAPirR/YoUMaQA==","signatures":[{"sig":"MEUCIQCgfHiFsYAbDlO7G9DED+TxEr+dezrwxJz2oPE1KFxp7AIgMSXapML1J4GTH4BXlMhsjMKHnCPLAwm4Rn1PuQp1lJg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59846,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfxMapCRA9TVsSAnZWagAAkgcQAI/lV2S0liCK6VxQXgM6\n5lrNT63uGW4Yv0NbaAbugn2pWHT3yzE5/q2Y47eR3eTaq3elFsOpxw7qE8VK\nAnZgksqguNaWcUROh/PLxBrP4LSaTaGbwLlJ/BYz6PbqvkDbhPHDu5D/AR9N\na46xHLzVk6uF3XZSyp/SV9V9GSai+x9wPDEXog4NK2YYR0lizvGN1LId7sCE\n2fHkOqj1TwrqjKmH5ieKnoL3Ri8k8BzC+0W55FlaoVZiF+W+QbwaWE1Qkise\nB/5fHDFDq0b4w12eoTCkvu0bl2voBQbeT2mMGmAwRq2QXrDD/wzdnzVdm8+1\ngrpu6wgix90dC6wOzE7etKW06ASC7Eu9Qz6Q8FvslEoRa8aJQ+nLhFWf9MbA\neWIcHP2jrjLwRWKy76zUTcEAhwgv/eukQSS5UyCPh/TKoknNgx23Swqz/a+S\ns+A65zywFVkhVjDWQf3cna31pTTsEkQB2+tgVqANJE7XjxWMOQRBGsM+7NHp\nCItCeLm5vOprnAKFkv3vVNfmJLez86ZWlBbOgKUDuz6x33K7Yj7OoH9emUvg\n2Ij/HVH/UPLg2IPNhtORNJCV015zyeGfGAe9PFJAVjvKdhi3sEZy3CWXr/Pz\nnZx6O//LQyDqRI83UmxKbwxWf0HOueyEGtV/5ClIL0gLdQUD/QYbR4r2YtXE\n7N/D\r\n=15EN\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b442fdb444648f81dc69cded1dbf25866d0076ac","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.0-canary-9cd51e3-1606731377063_1606731432852_0.05532842860695153","host":"s3://npm-registry-packages"}},"0.0.1-beta.1":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.1","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.1","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1cf014fa21e357edc27143b6ebbed158b4f49039","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.1.tgz","fileCount":8,"integrity":"sha512-YOPptx7vQKfVmjNnF3SGZ7lNrp6E11aR8nwgxP8StFZ9ze5S/fiwpG1LJ9E8F9JkuNWc75OBep27PUF+kJacTQ==","signatures":[{"sig":"MEYCIQDM0Pz/oG0dmzz5i2gZtggZSQI1WJshfdkABOkVPOCAlAIhAOb8/GD2O8IdZxm9i08jQ7TRO3kDKGjIhNMcq8yh8q4j","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59817,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfxMjnCRA9TVsSAnZWagAAZ7UP/3xtPP3a3Uf6uc6QN8oL\nSz5u7tstvrvRpvPyHB7G3c5wmbmUT8/nHRyAVZqGFMRlzyPuFOuxSbNyOHlu\nEoBAkeHX+jkv8+RnDsP80Zc8X7858cYcdFNl4o8Zw5GXJuJ+0xKKc6WedgNe\n+P+rb3+Ndg6XdI+dQEsH2nHxO+TTF+wYE04PaktwDudsqs61Nd8OyXsGoskQ\nYQFRc81lbKTuA404AARZ6JWnaJkQL/fAkscJJHlpTBAWGJn2Yf3dP+iHM79m\n9G9SCFJBCE6KFukEYGEA6diRnKncJUjlKbAz9WAAcZtnVcYayEp6aZHq/4PE\nPS0ERcgpHayfb10S2sOFlp2k4kwNU7Rw6rsS0KrbCa7D2vTV5InFe9E7T4Fr\nJAGEHFgVqb0K/h24pgUGR1+rXiVb6KvxPHcP6NLYeC217jsv72Ljr4Z90/Id\nNZu9bQZ05NELpXeL7/tIDKx1WJNRqWk1i7sc3tXoFHCIvAAbG2qLAfCjF/n4\nLuAvJsiV7wdy5AvBCB4+M2mvhsRf5E0SptCiZennHenU1/Wikcx+sAVYn4iI\n+yxS7n5ejSv1X64iznP0A8uEZSubeqaER93WC9TBeG+sOvxF6+sbN7dEEDvt\npG1KMmQrXenxNHpQJsssHH36lF7S9U+rBHyRMOvUUmhOlPxO9fk0hFVsPCxt\nOwQ8\r\n=yPep\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","gitHead":"bfdabf916fcb707c4282dff033942d8965f5805f","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.1_1606732006648_0.6051520142099078","host":"s3://npm-registry-packages"}},"0.0.1-beta.1-canary-2783bc8-1606732279589":{"name":"@iadvize-oss/opaque-union","version":"0.0.1-beta.1-canary-2783bc8-1606732279589","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@0.0.1-beta.1-canary-2783bc8-1606732279589","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"922d4642e79e156c1190d866c8ad7310d2204461","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-0.0.1-beta.1-canary-2783bc8-1606732279589.tgz","fileCount":8,"integrity":"sha512-NBmgoPmGoc4luEzhILoZlv6Ux1VnD3460VIHXFOqEkM/lWQpCNauVZIgBLMNW6kSgO46cTQNIDsxIt5Cm2OfOg==","signatures":[{"sig":"MEUCIQDYCa5igngobWDY05acq1GNnOF3yw1UBtg4DOjvcMLomQIgPZL2HEn7vzwI+krssrM/3wSwR2/8FND88H58PkuMzcU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59847,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfxMowCRA9TVsSAnZWagAAFcUQAIcSiNMOaZEV06fU8n0j\nJTpG5OTtZbDF6zxL0Z5g7/DVdZj8xwQPqLIZr8gBr4r+jDmSJx7moS0b02ao\np9sKJ/aUrlW5AYnjSiV5DyEJ51GIvTWXcwsV9Mg1AOUw9KVm3ne+UT/yPpa6\nYnemzJauSOEN6sg7Fun+DWNfCrzWI2wMZMRp2lMxfe24HyJphmET4VILongd\n8P11yT7AwQBgReTOn09RtSw3/iY/8pdcB88Hn/aGoD5nEiWWin78imxlB+Wq\nup3NiT3ygcIdBlErJdbZ7Dv3G5milr+aUzttCrZsPZFT1YdoHESUFhHcLcSB\nok8bcSj6odyvOP4hEWbWvDdnwcIR2jGbnX1GtMkPiKObImhdWfXKCL2Br0/l\nXnMg87CF+PvG4fbbGabxY5SU9PqmV85P+2JibaFxMEu2+lsRQhq/rO0d0Ir6\nwA/l/fGUhA+h9/Cf9qXFhIEwh8l2kC4iVcgJD4yRk+MiwCOdZ0sQP1jFs8oE\nBVOB1hhSai2LRGpCcf79Mp+Y68SxN2HxUyqKAUUgshwQt/WawoAmoRvTICyE\n0NiRNyF8/m9eX/wdbmEvUy5qtPZAveQVjFIeXdGHNpUahQ/t2jufSh+/4pl7\nWzDdVwgKLh1N32Qt1ywBaazHSDf5QY11Qhhw7uCOXbmwHYjzmVTrIW93Zev2\nXFAt\r\n=wRwK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4ac3af1e169887caeb06c7021263f833f1a11246","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_0.0.1-beta.1-canary-2783bc8-1606732279589_1606732336051_0.4762384208428798","host":"s3://npm-registry-packages"}},"1.0.0":{"name":"@iadvize-oss/opaque-union","version":"1.0.0","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"116e0ee0d314047bdb680573bd6d43d1e8f09552","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0.tgz","fileCount":8,"integrity":"sha512-U+Ox1YGFt8gKDtrM25oDjYdv8XiQkRY0mTom84bbqq2C1nq921cSuk4OgN7jgCvsrHdI3HzNIkV3THxyJTpCpg==","signatures":[{"sig":"MEQCIHRNU6YyCUD2ZhwX4xQHb8gcA1FoYkxr21s/h66FFA1vAiA1amLj+i7NEdmUN87C3qsk4mKBA/HzTTeAwOWuvPctkw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59906,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfxMwJCRA9TVsSAnZWagAAs+4QAIe+ywY+xa8wZ5R4QeBz\nyYfTxlAc6F/FhyePGOyF+/gFDj0/c3ciTVIO4RyCE1AKma6FVaWddWchyrNr\n6gzJXVeE4pgz2ueG3DveM0F8fp+FHv/zZzZHrRrFTQxzudWGSWvaktUmaBL1\ncanNgHBgBEzjAOnv+vgfNZw68UShfga6YCHTe23hwV7aYPfgSG+QMtVb9055\nR3HoQQCjX8Dv06/IdBHL/idGCkQY0Sr5S8SUXlabqvPD4bJzlLwDChcpf9v4\nlRkb3y2inIePs12YWVKDuvducai+tytHvgpBnztccJy+Gz//3gY8Dg5Y8Ryw\nL4M5OdtB4iUK+IRX3S74vKSTL5nFJavAcm20qzm5CFY4rVfdYtNWeFEG4ik4\nC5cCRS474G/GyupOBHnfJ9oO5gKaJCnRe0d1tnOORruIFDIWMKGyv7NLM1Gb\nvusXIn3qVZtaJU1OIeQH5uodIa+aAoLGp+n1hqR3wWT//Nsj9NwLsY0ASHX0\n3u0g+pSq3jsGHugxo9hGaNw4msazMEWr8uzLnWcsvYR+v/C70Yx6mqb+mXzm\nd/JJdID77v+EaykDZcLYkREIROIE+CirR7bk+N6lXOSxa9+m0WptCYj+KcqL\nJJ/GKwCKxlFKEAhsp8gqMVO6ulBiM5htheuDYTmXaJPeIVQnxvb/1d2lj/Rb\noISu\r\n=CVkm\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","gitHead":"bb3fd9eba1a520b66daaf3c9c660405ec8eba869","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0_1606732809353_0.3718698539794312","host":"s3://npm-registry-packages"}},"1.0.0-canary-1c65345-1607115545094":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-1c65345-1607115545094","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-1c65345-1607115545094","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c89f707b407fcaabe55a02322b55da1904a093ba","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-1c65345-1607115545094.tgz","fileCount":8,"integrity":"sha512-y9UDloXC7fYTvTdbadESpVCdljgYwDL+7hvhzgnoRFopOR0ZktBkC1+65Icc5A5dXgAiR2E2cI3JmnJe1jR7mw==","signatures":[{"sig":"MEQCIADdAUX0SGEMU7OG6ojDOiaY3o+j+Gui3Kpf8oGLgNtnAiAWgqUyUsnPH+TgXQ6MlJh4PyWI/NAdcSNyGkV06AgmmA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfyqNMCRA9TVsSAnZWagAAfFsP/Rd28AtE1eUzTGvnL7tI\nqz901cyPx9UYwjMDJT49Lkoutuz6+rlAfiTxM3zNMNqvI/LiKEuE/i1X0MVQ\n11emeqH5Z6//hmdhO0XFZ2gxWzXOy8phioKHQEWAKQSqmiq91KNXQpx6RTZg\nDxEuK1m3iEeip4YObhu41eWc+fjForZQ0FworgX+WhzaSEQIVrjlu4jpAFCF\nYU2kfI2VFaerQnq6Yhn+JaMR1zr2D+JxqmPodcZSrdezUyRTGTMk4CJ8X78k\n+E3W1Lkj008/Xo69W5EMA2Ot8LqAVp3FD5X5Jdy1yC/s5f2scc7Qg9LlzvGQ\nHDcll+UaotHj7kybQ6elpUO9LvFPByy+qlRzpYn+EEQg1zD65RCFUpHlVvJ1\nxq7dwtEMrFeUmftJ1NAYee2uyw6uJEd5rOKlT9DRpSbAwvVJTo2P9zDdHijL\nO6KcZWrzvA31TmcRc4X0e3eQOMqglJ2lye2uMVkhUVK8X4+M7pxJm841kSzK\nNX9UUtwCUw0VwXzTb8L2GcDuoTWUad/lVyDc4vp4ImgT3oM8ikOIRfLmxiQr\nULm4HdZcUmS9p6sI5t8l5q0u8ze6Ycf5Rtx4zSnpbTmY8hR4Tk75YSDFva13\nHHciuleWk6LBQYWdbsqL4FHCUrx8nYuLUm0YbRYyRQ0sLQnSPyJ9no1abOpd\nqTcq\r\n=djfi\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bd9cfba210c137b36a65e4bf5792c878fe3882f1","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-1c65345-1607115545094_1607115595832_0.6774566860631077","host":"s3://npm-registry-packages"}},"1.0.0-canary-fa8d5e2-1607812234888":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-fa8d5e2-1607812234888","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-fa8d5e2-1607812234888","maintainers":[{"name":"tgenissel","email":"thomas.genissel@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"pagury","email":"pagury@live.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ec3474ea833877e68816da8979289434a9e5f47c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-fa8d5e2-1607812234888.tgz","fileCount":8,"integrity":"sha512-Ym8GDC24Dl65fhWj8o9Xp72b6t30x+FubE0AHrKJBVoZez3fN/LBCYowTjPJcaCLmrf41IXMKrRUoP1TuNKiyg==","signatures":[{"sig":"MEUCIF7neBFeqAsret6i85jpcQvyl9JqTKGJ0BHrCid0CWk8AiEAv0GCice6kgPgoircApeuZWi0sn5BwAEXpBHC5QMpmFo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf1UTCCRA9TVsSAnZWagAAp4MP/RZAi5XdjXRLNtejywV/\nzKdYiVI1PhCut/Ss+uiEd51tzfjuULKgaLG4YxFMv7NmIsZeaBMPnO8Vjpcy\nCdOEHadxD4K5fqDDcySn6nJg+HOv1m5cMr5l2l4lZ7pfwhS+oZ23M5BJLDN7\nTJ6df5O7IPSK8xMabBBzmzZP//n6q8bkAstkC+U1j7B+u/YWpwzF+D7tBE75\niZcuvB90neEDabUbwbUEdLjr1fECUi+ouPvK1YsA0JqZD3WXbQbwg0tQX/uN\nlmRkGL14H7cy2Cu7/3kek4IVrnhaEVOCEVO1x+vXfgIaoIxesNBdUA9/KQf2\nAEowIvkZtldYH/u7LDtF+m/Pc26xFHeIRxK7mJbJkkZw8PppLKOFwKW9nKrN\nBUNNNWpBx2Y+kZi4cVka9PcQ3hfATEekpHVkBfct1wyUl+6fJGwRvoZCAG4+\ndp+qcdP6kVBgd0amXMFJJFbakv2hQ34EKx9phqYUT6mjYkhmso74suidrnbv\nkkq6Hit68nGFKP6x47vMk3R7fGRfkJtuN4m6kCd9xsu3KtlHXR7J3zUp9KCn\nHRGRfUo2pdVL4iBg15wqFHrlg1Ki9vZ06LgQ/BzGiE34EMvZX9FWkhv0Ajbq\nkPRMwwVJ+HqjZfmYpu93ls+mzc6+NSJTKeR+CoPs+50IYeUiovBVYdrQCfZt\nicBE\r\n=Xz8D\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b3c75c6ae06b52afd0d06a1fd0d5c08f3fef4b1e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-fa8d5e2-1607812234888_1607812290304_0.9317577322999231","host":"s3://npm-registry-packages"}},"1.0.0-canary-07fca8a-1608660098520":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-07fca8a-1608660098520","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-07fca8a-1608660098520","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"35975753f47e85bd9b0b1a0af07e8cc877dfe6fe","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-07fca8a-1608660098520.tgz","fileCount":8,"integrity":"sha512-hQfgWqeITi9Rreye1KsOcKEuXUawy78CZCyN3mZb28nsEjfdYsKr5UwQ6f/Z3IMZoeUjZuPIq02guk5dEhsOkw==","signatures":[{"sig":"MEUCIFFrfpq9DiRncw3K605VQDk+kvPA41Xhi8E24wBEngFIAiEA4nmhtYrB33ZkAO6HH+wJc5AipBck9mJgfYN4D+OltyA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4jSyCRA9TVsSAnZWagAArA4P/j8FvJH99muL3T4EFVcd\nboBd81k/hPyTl4zAgpCtu3miHqqV3locfstAq8LD4DqkqwfxrEafzYf5JbR0\ncQHzpYZUiuva/X5yGHybRRiFc+LACGsOFqw2Nr6BJlnqc8spwtmtbE8POOa5\niON3/0ZkjJ+WcM3yJ8T0wuDEKgveoVqwbnIevRi1upMOXxBxE9Bk9nNsbBky\nha0yBuuHFbESuBzAscfrFJbNL1RKfrJIlhneSv3PDKJED4UrQYHxlJwAkIC4\niRLJz/1OGrLL+kJXc9T3jGcQaVa5DCzKpsy+B2C0NURCuZl0gaKR6ZYatJsy\njPup/aCxZ+In4mmG2JWYbzhQcTOJ35myRC9KgI5UNp3WD/0ZbgXDlPDinhbD\nLZpO+D7Rb6gBIk/G9y3AGe+RpCgbqVe3GcESH+i0EAQhrJpdc/37p6BxqBiC\nduWXtnlQQgo20Mxwc+Afo8QA9txfAmV5iUNomXFQL/89rD5MVN7c+qO08qaI\n+HfpGgdYrBRRYiNhhTTfZgk0pfcq5NrAhevBJNs/S8ZX9nGPAce8nbeK6i0q\nbh2w6AQLgpWgxx194HNEfTe32EA6oZAh1ktv3qES0OlIQnBaG8WMQHRTvFRZ\nmWKnq17XDX/2kIxp+R+hU/Z8looOlyRmkfjylTMt+mRgDpM/EbjpC1w4JyYB\nNflF\r\n=r7p6\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"5f37a860d3d4fb0736bfb30d2c2814f1bb57627a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.8","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.23.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-07fca8a-1608660098520_1608660145390_0.5973694849484046","host":"s3://npm-registry-packages"}},"1.0.0-canary-25d80d2-1617264623120":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-25d80d2-1617264623120","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-25d80d2-1617264623120","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f4bc03c9490c0a007fa71454b721bf9ef4f2e5cf","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-25d80d2-1617264623120.tgz","fileCount":8,"integrity":"sha512-C4qsKjQG5yf7FrZhaD50HPId/TR5a0xA2vNdpy+9PGiDKRo0oY6V3sS+pobDx5rDldIM0+KjLOuuurJbm4rvWQ==","signatures":[{"sig":"MEUCIQCTk7ek30a6RW7YHSkY3jPn8IPYXxZYraHAuc7zJDBvvQIgOUmO+GafHGqlPvhJonUNmf+TH5FvAKHjbWWfIKPdYTM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgZYAwCRA9TVsSAnZWagAAY+wQAJ9lvJa0lWYqjTpmvTTs\nH/MdRNTsEaxP0LN/Kr3sMD4KAfdtlTRGoLICpHYclBanfamvCxLQJGF2vhw0\nMF3v0e+lPoFTPn8xNs3GuMGtggxzc4JgX7eaT+BQOi9vs2ytJD2FRlGq26tY\nkr4wOx+VqtsNDe2LcPAdLnppqJCoaNNeyyXOCabmlFukjGeJmMcWJsOUbRbC\nipk8+5eg/8UHTJoBqB/nbbi9ZAup7A4IdbSLHNrWKNyVlB63Wo7SoH4SEsjj\n+qWnvz4tZXG/QWgIhJ9eiZUvLcX4kcdoFE40uyM4hb1xIkLdOkG+4GMQdPiR\nRTslPKj5x6kkn/lHvPdqaTNXwRPRuYqr/XnVS1gLiwsg5s39L4CQiBgm+lq3\n+HwhpRiiZtFrH1QfCBRe9UnHjIfU/SNw0p2X0+fCfd6FS9ky1P8Tq8mRBFfo\nbRxjvioOroT02WRNjfLRgcMW9vRZJfa1h0N/GBYoROLA1WpycDD31c2Ji3hL\nh5jLrlOy4IggxavyWa5eeeun29rjLqKxf9DEauecLDkCgnx0Tpw+79nK42QN\nFGVXtEkb9FE9TSuYFOXwFCLmgruUYEQ0ChQqRrma9msRix9OOPHeklGWeN+v\nds6Vv82Z4MQlPL8vp+gqiPpDExgEGo1NcUyIWhaY32YUfekn/5qvveYNMERF\nGxPi\r\n=wgZU\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b0f706cedd09062fb3a9b632efe9283448810eb2","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.11","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.0","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-25d80d2-1617264623120_1617264686861_0.14907818013648821","host":"s3://npm-registry-packages"}},"1.0.0-canary-b9a82a0-1619732791781":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-b9a82a0-1619732791781","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-b9a82a0-1619732791781","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8d9784cc4984beb379666b856d6039f7c89b00a3","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-b9a82a0-1619732791781.tgz","fileCount":8,"integrity":"sha512-vyb6NSojWQCCHvl5T0iovt5RSaaoOh7LgG5S5TbYKkBmVqHd7XYeWi4D0dWlTkEXnFkQZtBNUJYycbaVGzqQfg==","signatures":[{"sig":"MEYCIQCkc+ZXuitARYDKEqfYULEfmxYmLSCnFLI+h5B+mfUB5wIhAMiKVeZ03im8PWHjGa2u7J0DtvQAZa27l1+CAns8M8vq","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiylqCRA9TVsSAnZWagAAlHMP/3U7HLB+DmxcvYuxvJnt\nrgYdIbwLZdNtLs76kBirYkfxi/HqcfYfB+FXOsLvFHw8un8HDViUqdotOCaC\ncZbeGkutb8nguqldMzZ3uMvV5mwFoeE9TdnoUOSmuJVlibgusibuSnEdhIbH\nKRnZ//Z7FyIoX7dCCQlDGMaMzi6q61KG5thyjrdJuaQexQ+xYiQG+s+PHu75\n9Ds1kY6uVSJ6pQhzVwsmRC23I1Kv1vbDZHZQ0jNBVPoW3v3re/BVo5/2SurM\n4sln8TwfrJ37c2NI8uPI/GmBtssoVcZXCBmmmmIeVAR9s27WjE4MZKrJIArQ\n+O4kijuUnqhiHeiELEKOo38UyJnlNSG9BtvVpbsUUy0nVTOo63ms9/mHA3UW\nqx3sXLW3IxH2oMTKdTSLBUph0cTxG/z0UWlht2mqoMDh9GO0leHivOV6/lxf\nSEaGAC6Z23nux4qtYw9NPo4VQ2MTJSq2QKbCLjePGF8GXwDvmJrtZMKDBbKF\nUAnupkYk1H9IzrS6wiAO2lA/R5jn8ZNrNPkbrFrzTt85QmBpOBXvgMTPlzB9\nt/xsBHVAFmO21Y8Uu0wii+HsfpKeNDWXN4nhgsOWzsDdDmZfRGFIj16vhTtj\n8GFdKb5PzXl1eVSdKb+kssQsULmnwi+5Vci92nodjbIXQWZ/zJWxXJPXkkI8\n2Rlx\r\n=P7U2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"dc8073b5d58e8b32598bf74e7d2c7df6710a9226","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-b9a82a0-1619732791781_1619732840933_0.5300951873402322","host":"s3://npm-registry-packages"}},"1.0.0-canary-cfb0616-1622558091338":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-cfb0616-1622558091338","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-cfb0616-1622558091338","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f31ece24e3db4fa8db3ac647c8cdf227e3051c5d","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-cfb0616-1622558091338.tgz","fileCount":8,"integrity":"sha512-rWSMh3VC/zOFkWTYfacjDZZ0I5j4rrbompI4Jta6CXkuxXX/KI6xV79gU13ldm23mrkDW6RosSx3e9FmZOltwg==","signatures":[{"sig":"MEUCIC8dmCn222/57c5ii3baOKO1CnVda2ivgK2Gm7wrGtrhAiEA/yF4UuLDFXeECf8VUdoVDtUoeiMLh4Aqoaw3n6e2T/M=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtkXCCRA9TVsSAnZWagAARqAP/0drNUSkwUDAhMk//Eny\nOApPT5CqVXsGkuFtSRvF1Bkp/3CjBopBxL0yxGDzAB3QSc/aRy+TZ6vBWZio\nwqIZezOqkgnbgLvVyCDlDm0MO4xPVeXH/n+jYEYeXpNZUyNKLkkPVNIZLqWd\nEdUERJ/rZxMeUN5GELMmUztLzxkLeGCo+LFX9Lkx65j9iBfLfOTT/Dq6pVKN\n7SMAmSrGwPHkDDZniJNAg5VPDtBiZVS9PoX3bjGxM/nZtX+sY73OK5pq+d+/\nnAeR4O0NnRZs9jUGGjqU7MKZyZ4dy5qJZ5LZZaB/mSZ0bGBHMKiyYxecPGlr\n/2t3vNZlQitEOVE+NkpGBdppjkuMqY486iFe2/4ywjBg2SNoozIQZvfVNoZr\nZmD3eqs9XkMN2f9J82qJpEJkW/ASdPtV6a+KdXWyZt2Z/OXdsYpB1i/aX8vz\ndvsuYxxAVMyralQ30IA8x3tHqkNJbE7V/x+63pBZ6LH2DmnPZYmHam46P+eE\nwdYFQvAEZRX58v1nsL1GrQqMULwf3urHqY1TyOogT9thgoN4GWvOZ47ytYU4\nPHA5CUSlcCSnJZeZ1XI94Izb+zUyhi3P0dcmZPzqNup9gtXiPY7P1MBm6kw5\nTK2Im8NdN+SvJ0gmo82xxb5KWyBSqNlTM/C6xsztKPOfcLXwjyQP1boifT5f\nUr5A\r\n=WBSz\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"1c177282f87f080689480f65d2bbe21a2df0b706","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-cfb0616-1622558091338_1622558146091_0.18921113730766903","host":"s3://npm-registry-packages"}},"1.0.0-canary-cfb0616-1622558101081":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-cfb0616-1622558101081","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-cfb0616-1622558101081","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ae5920e0b741d732685008265379acabb49c5aef","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-cfb0616-1622558101081.tgz","fileCount":8,"integrity":"sha512-v729d9Y9BGcReZVTxkltnVrgeBdhxpQwbFzehVAg3kD3y/7Z8nnU0itbxlbcBUYOanm9UUeEd3Ay9ACUFFCmtA==","signatures":[{"sig":"MEUCIQDiUW4JISGsfLN3a7HR2qlA4JfKUOVhKoVBuy8VS+BXUAIgUWYTwks1TOtrankoW1QkeaPxtBIDtgq2hQlbcUft8dU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59939,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtkXMCRA9TVsSAnZWagAATYsQAJCTLXD0CV35uPCmeI38\nzbGLC3roaOJ8n8adgemhAx1D9kOrFhtdYIQA0ZwMv7I1qWHRomcAShyiN+iC\n3fT1pMWrZpq+xPkga3Glwmg+E5W0v5TznmS5u67LKCQ6w41V9wGjsfLZnGmx\nKQRQ5oWZXuat02OH6Xd6blO6YoITT/o6FtGV1G4IPtutpVtZ//Ntu6tY7hne\nqPhR2Qoell3KIYgQ6vqXoYC1ah/slxFINsJ7fIsc6VaOocRhM+sFfXbH+RNZ\nSj7wsD0/NTcTfs/bujGmItkpOHtsQgsz4GzUTfVSbeF7KBNTgUxQhMXj5N3D\nYt6LJ6e6X4WgpfIKkVVCtBxrVv8K+h1i8sOO5XJaMuEmPOOSZb30HpcesOHq\nqABwrObpaeYF5S3ZPESIIOybVbbW3+ETMwvdcfvASyTC9FAVp87D6wOUHGvh\nbUtnSHneIE32AeSN+I+YFusrZW8rME9YjP4WP4zlmEzkjIiqKuR6pEN71YdR\nUEE18x/yUoAd/dOHxe/yEZgQFmADQAUDkfbmtB2hblYeLCVwosgkgDXNFIj5\nurBk0Ei/Pobrgnnjy+3TPK/GH8WpgevKdIz54oAj1PTxvNrpBzW/jo4Ru+Pm\nBj/uOPdgBUOxoMUo/pW+6paX3rlZZZ4vplxF0hO0fC1K1SX0mmb9Azeyn+DP\nBzGv\r\n=o4az\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b8956a5cf11a8e0d5ab632581fb0aa6ca292ccd3","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-cfb0616-1622558101081_1622558155853_0.3724707073729099","host":"s3://npm-registry-packages"}},"1.0.0-canary-22d3af7-1622558336716":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-22d3af7-1622558336716","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-22d3af7-1622558336716","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c076f96ffe83813d37badc114ba70797c73f34d8","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-22d3af7-1622558336716.tgz","fileCount":8,"integrity":"sha512-kq9o5/V+XIG71Ofx2aIowqZe/VdoSv5I5pXTH0pBObfsZz3ncD4SryDVaRF8ajWoeSxCU4Y+hNdUL9MS3T9VNQ==","signatures":[{"sig":"MEQCICmb5tquJb+9UznF/4qxAunCLMUeNIc+UlkwGBoTenwYAiB5FwzHFvF+VV76Xv7gCi660SWCrDHhfGPh/Bd65UOnFA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtka6CRA9TVsSAnZWagAAfoYP/A6URKILILXIqfqlx59g\n1mmEK1i3w2mZaqFIbVGKv+LTAJjBconsXa6hw1SouQKie2p9F01FMKoRg43l\n6YBY0O7MwYVdA2KKCWWk1/JkBIiz5g3gFVthaF131GJcq5imhRDMN6TCR8pH\niz/P0AdSqsUa4TWhskEPfb1oqebo9TwRw/2MCioffzeSxPZB4AA0g1uH4bSi\nVkjMzuVxbw3ZFZajNcE3WJkkRlETy4Qw9rEEHmZRRb+W0BAWcBM7FubQic3l\nk3iGK9faaUiYffCHCG1Jigs5CqFkYd678GbWArKxJUPXI50IT9oxaqc0AZ4D\nlyODp8EVV94E/ZN19q5VD7G4fQ2Ea0ZWy6QuP0JVuSDqiUS5I6/4Ovwb4u8l\nZKiAv1G/LE1abW3qJwuDQ9ao7ffbbYTsfhxFHiwdqT0rkxEN9mWDFs2HzdqB\np9XU7c0+SKnp9pGAa52wUO2TvGbw2v1oIt5MdDUYYF781ADbTqQqdIhMBilq\n9UrlbtRW5QggygUK6sIjB29ywtjIuIm3oP4wZUZJW9z3c1fgwQvifKrepwns\nzbK6UQ0QKKv4OMP+iMWQzyp6d6DKGY2SNu4VXFTaDQ2gFLefTRigO9Eoi51g\nk+aZ9o2sR8AY2YW0TjQ44Wgdlf/8RQO2VaVVCx5rK4bLATWO3cv5DPIdF8ni\n3374\r\n=/UGF\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bc237240d1aa89208aae19c3bdf38c396344c686","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-22d3af7-1622558336716_1622558393802_0.23812156726202138","host":"s3://npm-registry-packages"}},"1.0.0-canary-22d3af7-1622558474645":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-22d3af7-1622558474645","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-22d3af7-1622558474645","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"0435d42a2332832b9ec89139f3b244d0179837d6","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-22d3af7-1622558474645.tgz","fileCount":8,"integrity":"sha512-QVtNO8pzMQX2yw0Bv3kL+WDWkCn7p/iAcRfLe2sZXXbNbklMp1vMgcYQsHsILSuoWeoVzJSYZQQchKGMENxI6Q==","signatures":[{"sig":"MEYCIQDztdyKcuPqtR5FyQkkO18r7octzeRAnTAoHS8Z8ZEyTwIhAJ/nd7xVfCW5bjhvWwrzzo5YjwLT1ep8lxOpDWg5tPwA","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtkc2CRA9TVsSAnZWagAAUhEP/2+2FZ0o03y9P4tNEccX\nosCi3AEVJtcVBBlv9itTAWiNG6RwVLUiowbB2UWiQcQzB4IxIgqKWUaigxKM\ngjBfMN7ExweYDqm6nvHFGCZ2GMQOdodrngTFtjv5ejfgP9Ld1py2rA6AE5fa\nF6RE4ACesN8CMatnSFa6H3gE6BvU0brEPac2IhpeYjhhHyUKoPnPIUnb+oVw\nSj7eoY2rwhjVjpzq6P4AqH+v8AUFrwpa0DhsmE9CScRXhq0F5c4ftZCvhr5I\nB3Cvzlz6VIdG8kma4r6P0ciLr7djKhpd+wEUz209YM80tyXDdL3EkiAqjNMZ\n7epPsQDveUQu0+TQPtUr92B8BrENrshcFcxVMSrD4v8e/U2YERCTsMmeDeCH\nU/YToPOOEaI1Tq27NdaynMWxqeV2Kq8BXipC15YPb6obvpS/VPrpdbH9SS/J\nWYD35WNQAxS0oAgTu0F1qSpv5y+gD1yTdTtGGo+YkvtspQ5by+I1nYu7cxdp\nVLQW3qcRqvFZaIYu+r1xODIn1jLBTa0zVu9T46nWF1byT1y56TDFXDWjrCoI\nZp6wPHNlODEq6DbO+Qdn6kv/erHTT1zmdnCf6m4sqg0HTiCjk973QSPjisTR\n7Fz9vY6khEVHRj4hQtzXqpvwEZsA6NgYzFPJdvOPVKJYStPgHXlXV2fFNpDJ\nzADX\r\n=mAYg\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"52aa226bda70d6cd9c13d8b1f76d1bfc52e5a7da","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-22d3af7-1622558474645_1622558518089_0.5061118672814804","host":"s3://npm-registry-packages"}},"1.0.0-canary-04903b0-1622558756695":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-04903b0-1622558756695","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-04903b0-1622558756695","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"e60e5403172828ca564a4aceaa2ea81541cb3e3e","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-04903b0-1622558756695.tgz","fileCount":8,"integrity":"sha512-15Lmi0tKs7O8SvC85h9pNtKhphQJ2e0iOmv2+5mHaY8hkaMb3zbCCt3VIHVqT7zyTnOGh3rOcmChtMJ6WtIVAw==","signatures":[{"sig":"MEYCIQDqmlkWpnX/RmJSdKpw623cAO4oErpN9fzCus2BDtx3swIhAN97rE0c3k1PE1Fjbfj+HtIv9SWDKBU1u4Ns8vk8AndO","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtkhxCRA9TVsSAnZWagAALxUP/0LH9XwtAoDlTomoqpbw\nI7RIs04DYq7tT8By+BFNzljL7Ds08vdLQCRJGiQGVSCEon2SArmH0D5oQJN2\nGFZcgTQPfLyPmxBaLa2UqPYss9e0ngq2xz7sJCMIfpxd4XFvdY8rB0w3gD39\nqLw1FDY//0L/KvrQJwDDU6pvbqdk3TITRMk2cYLCfC76WcSn573Awaigm/rq\nTRctqXMji2q/3VPNw/VJeDVZR/2EiGxAJk95ZzkCQPG7EITNSD45VotDhz5e\ny9HbWcI2sGMXFhnlTvqaLSDsm1m7u2NyUnrz9iwnIlDOEAO4IvytWPtH/cu3\nZoH9W8PzOC9CFR6bCgAflhSCEDUm1zlXk+F2jKHlJQdZAzr8XARbnQAS2y3g\neiab56o6OMy1CzYa5B61/AMxgqQxN9y+1juQyFJfn6kbeR2FZbvp0gKC/uoS\nm6Fjs5ufolUYQa/Xq63Sv9dVelMNvKRzG6TeE6Xufv0QZPxX4hCCNbk9N9+g\nNaG5vz3Yh/is4Hts6YI5FFnkHc7QxuYykfs3ndpsptZm9OlYnJB1c4JuWSvR\nsfkA/MA6qMcs2VXP2gIPM113Naqp+tYUm39fV+U6FFHyI0Vnf2NLdgOvfw5M\n+FfAS0Jv4Q0GLAPEvVH5Ms41cOjmQaLGfo0d3cIiAHb9iN9QB/MnkSYNe3Ys\nI4wG\r\n=KUP5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"92c58d319c4502904ccfd0996af6e214cb758292","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-04903b0-1622558756695_1622558833338_0.42289099659641693","host":"s3://npm-registry-packages"}},"1.0.0-canary-2c5d75e-1622559635057":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-2c5d75e-1622559635057","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-2c5d75e-1622559635057","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"d39c75c4cf08aecbcecb476b1f87c517ec79ef48","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-2c5d75e-1622559635057.tgz","fileCount":8,"integrity":"sha512-/y18NEFyOIOn1BMEZ0B2m9KOUvgKg2FN/WfwFw4U2y56K47Lxe/cXRMawWxFOr1SU+c1Il0gNlQfv/wM/A5Kfw==","signatures":[{"sig":"MEQCIHVVLnJejaaWQ1/7wEf3+XfXt+2gfpkk0g0zt6xs1ioLAiB20vwaz6c1yApornidvvUILlyT+xrG3zconnNpkgd+Xw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtkvUCRA9TVsSAnZWagAA7B8P/R+KZ29VeJGmTZiGvqwD\nj53YKLgKznl7WcdWJ1MX61DsqJOXk61uZD2yCy97DAUtGQSzzMVkAbiuwUWs\niniVmXPzraC+QUZIBKC2rOEFMQUrqAS/MOpgL8AAyCyFLIIVvLIW+WGhebP8\n+Gwxd1ZyxVA/H5xbQlZ/Ebhd0n/7cfWWfDwOkKIdQl1ZfUm5C0E7VaTdb6OM\nlcviMPDbiWCVMLkFNamFA0NAIrhQ8eirUOK5w6kQnuzWE6EK7hex1XQ9V8Mi\n37mmu/gpN6MB1HgOU2TnUEyA4zYum7kmL1kCm3rBLftuq8tnlwallPnxVJ/x\nsvBn+tfj2ZOPTMRq7eMgWn8DjezAeJDrEbpArzY4A+vUSH8CLnBUwrQzz3Ra\nfWl+EfOpW1zVAjIawXptx7xB1dUw5JT8lPQz2XtOUJIJQmunnt3LzpOzp8bi\nPyMv8Qnrmt38uwQ++lRNeHd63xf0xtXKGQ6ZQphfYWBqpZjPwUbtpp+LAzkN\neeQrtvi57f/E270ZCY+Vg3IqADEkVTH6yHBj2USJKHHslMRNujY/lrzR+KDd\nYvTJYvgCJiimuaStXTvabARs3Qg6yLrjZ2LyQwdngSOp5UF/A5c2gowyOaeR\n9aNpKappYJ16K+WlpoI3eS7jkrzctfqugaOJtgSnLqncrXOTyFwRNi1TZIlS\nWsaf\r\n=TAVA\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bcd6f75f4f9f9a34ca1f6eb1c0e9125700bd1ce5","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.13.1","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-2c5d75e-1622559635057_1622559699584_0.7191088985790028","host":"s3://npm-registry-packages"}},"1.0.0-canary-2741463-1622560304938":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-2741463-1622560304938","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-2741463-1622560304938","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"225e0a0aa83b377eded746b684304aab1490e646","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-2741463-1622560304938.tgz","fileCount":8,"integrity":"sha512-x46sU4bgtt7M7Z9OTClUdrju0LVBf25wG6qfBr23Pqhcq6OvCLYmK/gLJdqm6Ponnfhzd4VdMlY6pDzh8kHkXA==","signatures":[{"sig":"MEQCIDSO2zREVzh+PBGRBGasJaXd5kL0f/EUtMMHlYl4Ab3eAiBSY4uD4ADVJQj78EDfDr2S68hQOWVYVdT7HrZuobVMhg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59939,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtk5fCRA9TVsSAnZWagAAstcP/jmgzw7oXoPXnwefYvDl\n3L4Gq3rmtBEDYLKyS9BNywi6LTzJyXSJvvG7qZpQEj5cjqzDBX3bqRM2FK0g\nKFx3xG20Yd1fCoxAD/MGnfBHbbnjySaMdN56sMkDpVogq9QyJGpuJHakLAIx\ndINbiLW2jR1Uf/n+MkR5bzNLhNHIY/uZE+O3rpk6OSf6P9Y0bpIJ6a0O9TYa\njjHuopsSegWk0OlrpFXJLewdB93hjXoJ5VqGPFFIlnvZgkQv6gx9xYrx/wRe\nR0nZ4PVrb0qh2NHYTw2KNuWgkTFfCEaJ2OLbKMLN0FYhb9AUNYlGgZNTnyu7\nVPGYFAU5vkwCnnDiGSZM/6w0WEN1/E88I1nteq11g19Vu7xoc8KCENLRhVmA\nvFgcY8Ahbl2gxhSx6zsIDcIPQgDtuD4Z55XbfVYMrfR8vqELvNedQfAmbqGl\no+sMc/9qox8zleri8kdtgXGA4gMQ0t5Twfn7/cjFkGv0/J2uNLMUx9JYQX06\nw+cJ0cyE+Upgwq1gK47RLtgYb/tTEDbhneWq4izert1eMrGX7TVFylX5+ISJ\nEuckI2M0dUGbt+PRbwH33qAVNy8lmpdteb2xg5yD+WP6drMdzRSLqUIZzLQs\nmbLFragCUNmR36uTgCgK//yjgwmV/OYCCxVv5Mzg5OGLy2tDmmVSdS4AMeIs\nkTP0\r\n=3lcf\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"df7127697369ef0d890adbf154ec8b6f68097153","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-2741463-1622560304938_1622560350548_0.23859536789971303","host":"s3://npm-registry-packages"}},"1.0.0-canary-de4c831-1622560624810":{"name":"@iadvize-oss/opaque-union","version":"1.0.0-canary-de4c831-1622560624810","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.0-canary-de4c831-1622560624810","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"2defaef8b7acc804e8c34bcaa10f1d5e72a736ab","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.0-canary-de4c831-1622560624810.tgz","fileCount":8,"integrity":"sha512-dcwg6srPHl4l49kYm5RDmIQXt6Uz3W0WU1JH2TodN3OgxsOZWtnisKSMdNQ/afM8lrcLQF4F3chYVc5zhBwZvw==","signatures":[{"sig":"MEUCIGWR2+HAX/XpoDBBlnqlxo3Wo8Hi/sd0I5ZmC5CNzSfvAiEAyUOakhuJ7986o6GvWuUpsuyny8FKaJr9ll5c1LqV1NQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59964,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtk+eCRA9TVsSAnZWagAA1kMP/1DJWmW8+PfH95xWZJEl\nCRRcbp196Jm9q+5V/BAuqN5pmP5pMnjA5te6P11OUImPZDIKmmo2Ohs5srC+\nR26Rzn4LwyntjQyX5I4fHYH7ZJqp0+1gIziYnZt2xnJ4TqL/12BwarkxAq1g\nqSbe7x6rnOoi8UW5gpzNFil/QKbZ7gvE0dIuzyoGghjaMEy75OeUhGFTOUQp\nOY3E+ieXCdDWRHeGB1nqZQlsnNdaa6ZhOW5sVZHdO3nZgXlcnU0xnsf8sWNV\nrttCC7wnuNJI6VSO7xw5wzhntuL1oSc/rr+ZbceO5Ux7wJDTI+3tTuAxbOL2\npvIdMjDv2aHTVwH9HQnYdn2jnc/C+HQFp6TyzsFdpuHEsmuTQ1Sh62hVUWy8\nxWpuNEFeWf3xg2GwxpCFKTtOpdl6KpVhfhsPU1GH5gdtZmz24aXe/GwOy5vX\nEZW/Kg5EhMYOYYy3rl3146vIc8DtFn9n7/esiMkF7GOfXPge9WCQFcBxz3h8\npWDE9AVbCw/AO8BeU1O6J2XZxsG6l1KzhxCF32CKnq/FFWn/ZM+KA/ztiAOJ\nS/8lku+4W46Wx9cFnLb1YxUSCh1e4Vbm7pNu9ZOQilEbf58XR9QwPfGuWUuw\nqEwpjO6FtxtPuRbDt6EfQn//YLN1MllsvEFgS8m6uE+O9aMRXY4Sr47nXEQg\naBb/\r\n=0ZmJ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"62e11919dc10837a3011988fce6ab3cfc4c6d297","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.0-canary-de4c831-1622560624810_1622560669829_0.6583929184971911","host":"s3://npm-registry-packages"}},"1.0.1":{"name":"@iadvize-oss/opaque-union","version":"1.0.1","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"178f012f219280f844ff16b7f33592afbe382177","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1.tgz","fileCount":8,"integrity":"sha512-jpfAeJQZkyk7w0jfIlwIUR4T6DJycR3O9/8r3Xkl2SrOYaKs9cegYipL/x5I6nAErh5yLs8DAMb1BXrxgdIZdQ==","signatures":[{"sig":"MEQCIHI0fRfNrvCOnDUUuNiJRuBCXyw5+W2LvYFoD7XKVOpkAiB9r1qZMY7uQSuvENtr+bjEHHnUA5ezqobcFPfWXTB6Ng==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60031,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtledCRA9TVsSAnZWagAAKYIP/16wWNQdUe6jhXAylTY3\nyuruEe5hfJvtThtHFPIy29zVwCN5LOehvwvmmNswFCaUndTLzgPy1ZLVYZcn\nTBvKMSIiWSgBRKz1hlk2eM1Wt4frj/YNoEGWmoZdZq8+dnPNv0tzpXDv8P3x\nE8kds4hjm0Wdccm1MDHCfm+FMMiHIjBE8gGHijMqwZzW10Ja+aU61l1H7w4s\n7AjXwo3nJF9sDpazHVrjsyiiz4Ixxrs7ftym2BUpp8b2QKx0BubjUBEk0I9A\nPXkMuB6rX/GFgsPlQ4rs7qd7Dv3aSoia82AGmMrdJJuhThSTDlqaETdslb+0\nUEuN6PDmzd6qG4ZiELGLjqQIU1xm9FwroSjy3l03siKi6K4wkn/ExvZXBzrt\nsaXvGGxPTh00uVoAjNeN2oNTpoxucp9T4G9KOotscu3r5OglFApUfTN0o+K3\np3+fyP904QFic/zm9mFp/efRUqoYtLzG5gfEB5ezRpe2gSiHk2MDi802fKdZ\nDEzVv+uSClrGf+Xc8RTFrgb34KdlzASTeWhZV6NGdlviDmXPU5iFR++IpqVb\nHuzRrmvNyYHDQlEUKnj+Zqqz19+tNkD2m6VzSGn0RMzu8GVOcSBGcCJrx0nF\nUiRLyh8HbhW+yDD16A97Xw72wOWxbXnrR3bBAJxTq8euZ0y9w0SyO15uvgc5\n/dbL\r\n=fbn5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","gitHead":"e8289549fa75c4b6f815f8ce47647c925f9fd9e0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1_1622562716722_0.8332460556565426","host":"s3://npm-registry-packages"}},"1.0.1-canary-e828954-1622599379480":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-e828954-1622599379480","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-e828954-1622599379480","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8190a7de5889e602089f460381a9b00da83081de","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-e828954-1622599379480.tgz","fileCount":8,"integrity":"sha512-dQ+zZYwOFpcmYF+fmjd8To0KFJTNuS3r0/Jnsfk64/TcCCOIQwtJPj7IiG53RBPXxNEoRgQZKodtjqiKuiiPng==","signatures":[{"sig":"MEUCIQCgDyWkxzPfiGyot3mlBH0PXO07sT+GmqY+o2CeGbieZQIgF5eylQ7NFrqUPnvppuQdohb1HeE/Qr1zcY5wrG0akRQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60060,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtucJCRA9TVsSAnZWagAAV2MP/3/a5gQzmF7yRh5qz6qC\n4mV5YschbH1OwyywsxnipQob5FTf0MmCWnPol4BoYzAPNtmKrYZclh0R1MTH\nNDOdLBgIpSbNMcYuW7GUkFdTZT2uEjVp3s1p1twJcoQbDMcJMPCylQt0K5u8\nGde8Ky8CmTO4gGH5Px9h38rX21GLVmKThYxnJ59CwdvS6sFclkquynTUSob0\nM4C0yT0AGdIF9L5vPBjc9N8Lp0UvjsW7uvbR+CoIXXUpIZ43Q6TyLd0hOFSI\nz3Qzpe7JY1u4LVDtIv3BQpSfRZPWtG3rj8VA08FvbPwZ3ws/prp/SweA46qT\nb3/ut00j9XZafKVKTqrP82isj4G72+9b0yhra3tsWE3oZSvHm8u46eJWnT2M\nZsFjzgmnL+VDdesvWkMguQ3m1BD1PkU6JbscIB66gJT2ROmLU6ecBoLpYhrs\ngPxckqX8LdYaUK7Ox56UepcrEG47JaFZXU5dbtCofVq8g+k12W37tZs3cyns\nwnHb8EpXShbV8FV5zshWUO/g+M4ecjBTcGF6Egot6+O7Dk0YI3J/Sfo3h549\nTG+eZiCwHAbFrX4Ia9JSMeYv4t2jFaax5jnXQDwv4ynCADCFB/Dfsji2Jhx/\nTYEdMrjDIAN0kmOKpdUC4AuDnsAvtWZUIVXLVvX8vNfDUaLvZg1/bRbHj8Wc\nwMFT\r\n=nvF6\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9d8b56dd7394e3f5710c7513ad17a9444df6a8d7","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-e828954-1622599379480_1622599432775_0.7901979885146755","host":"s3://npm-registry-packages"}},"1.0.1-canary-e828954-1622599401422":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-e828954-1622599401422","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-e828954-1622599401422","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"02986fef82388ce066cefa81ea5ba2978fa5a322","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-e828954-1622599401422.tgz","fileCount":8,"integrity":"sha512-ZsTa/qi+ruWr80CUuJ3EpBd2+USQRkzLClonrTrpr3A6wVPhcqE7OJhZzrhwvtAEffv3bZqzqZZ9UqgPYEStyA==","signatures":[{"sig":"MEUCID8O2X68bHYWFX8U6h40fAxzOwZFsEzkcuqfGN5fysa5AiEA2hD+4BhPQ4DsPHBJbiFPIdq6Xsp68/S6Bb1cqho4lPw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60060,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtucnCRA9TVsSAnZWagAAydcP/RKmEr03DfYqJR3ZWPQc\nK61kMGK0K4o8x1tnF6emTmsNZxmr2jGGMxiQm3A5GwEcy4Tq8sCA5aLJ4rPR\nx5LozYywOYveXdndtqBUGKOC4Wt0w9f2ZXK5omODox3VLNQ5qBCB4hAxvO8S\nBpVp2AOs/yNJGx4E0kHlTvm+AT7sYdDmjB1oA6efVYEkOa2LrgzHQGPDFAkq\n+BuWUbX4IfYx+QmJsReNEmr70yE3n+Hz9w9jUrFHk8Omt/owVaUR8Lx3zVTu\n39Sabm5XGVeIrHb+Nc9h9bdFyPpMh7s2zdfETlCV5nEwktDEozV9PCS6Zt63\nOrHijWntjSRF9PmLmECxcpz4L0PHQ87X5QJKv/yC4nE9q69srUQ9kgx17JOi\n9ZyZgJKuAD08GeuGv3VKaJIbc/yrc+SqRi+FLYtjA2W5UlHN2YOwmVnpHbmd\ndf1DWj3ixQDc9AgUxVfciV53zPgcPqs7zTWhbsuWmIDptFtSoUzksiawJVDy\nnH5GDRcKSeTHyynMO516KHKWOQGkqSZM53xyJ6m7637P+u+sFmZTJRbSt5Va\naMrA+FQVzPeI/UGTRaCXhiRLVzfx59hy76nt5MscemIsS2btIcUh6/jMJ2K8\nVBO93pA7mC2rwWIakkphlM64wbX2PnP/tcWWpoyDPE4KHjV0hWywvvNPZrwx\nMa3R\r\n=HHDw\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"13f7a17580b3f941154cb598568848f5b7482f1f","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-e828954-1622599401422_1622599462500_0.3776814959296064","host":"s3://npm-registry-packages"}},"1.0.1-canary-e828954-1622599428397":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-e828954-1622599428397","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-e828954-1622599428397","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"fbead0f3ad0c8e6b37502a84a4aa3848c158409c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-e828954-1622599428397.tgz","fileCount":8,"integrity":"sha512-5GLZnmeeiX+MtkR1L7vrP9KBApOHLhVAYyvbvXlU156QU6jy+XH6yMpyS4uZWs1pUwJ+uC1ZgtOUtky42UmKJw==","signatures":[{"sig":"MEQCIHdk1e7/jRUhldyK35BJjPc1Nc9QDNNULUO+nEbSkUl8AiBNjCNva0hecDQpTl7IS8+OAN5iXhUH92VknT/pqVt54g==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtudACRA9TVsSAnZWagAAORkP/3oefXhMVGAlTNPgVhTT\n18LcJb3q2KZtCe00kSNgRAqgd/3VAhiGquNLF8mV36tZQbOKtVj7MLsx1wPt\n3bDdh8dH9577zoWO+hWM3fNxBnt25ZPZp6GDNYb4D1/b7KfkpWoAZqoX94Ef\nQ8J8lU7faLMlJ18tScIAyJTkGESP/Llh3qShmgbNxykL2JEj8mYm3nLGsCEe\n5V+C8I/DUbH79K1GRD+RSrNkoEA+Ivlwa5jDwlvUDGIuPvjtPgbLxz0TvU0v\n9wswZ6+IJ1VUVBeQ11ReagCE7G/vbuGW4C6oVwy8jOzAvOtJyOYEEXyY4/6O\nQul9TjuyiUVF/Y+aktjyu55HgpILaTK1JCZXwm6qcLdpOXS7IfOYmHp6jVPi\nbp5sLWYgGkoO1Pu1h1AgZB1M/ZEtR7JjtnvAHtALx3qBoMReQvBYhrUclyQm\nFCjiEHFavZ+MrhzvSNliXJ21lNoV05eI2P9kaL1ff6FjGVizIlee6OBrfdw/\nFNXQWRaI29OBeU7DZeBAE34b7sY04iOKLD9N/V3HTK14qYNpkkB19sKVJ8e2\nHAXjqAAh0g5uXJ1TUrk6wBgOO/ixdeZG4s7i3BziNSCrKuK5lqqZVMbPEFog\nBQohO3/9UJQ7lp9wMg/3xRAhU6Xq9d6Lfm8z1mA7dO+LthXSBql0XJfgx9p7\nENLt\r\n=sPOe\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"e3d83244cb083e9c3f3e146bfe22c4906e670e9c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-e828954-1622599428397_1622599487925_0.9615543568698879","host":"s3://npm-registry-packages"}},"1.0.1-canary-e828954-1622599460736":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-e828954-1622599460736","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-e828954-1622599460736","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"2ea1ce324f7de6db6d820d1cf5972191200b09ad","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-e828954-1622599460736.tgz","fileCount":8,"integrity":"sha512-jG3zFZ5d5yO1FD6uF67Sqw1f46KoPUkT+aEsy0AsPeDNfO/zGTo6KvUjgsodK0rU8MPWLbk6dcYAKZzWWbocfA==","signatures":[{"sig":"MEQCIBjqisL/k98Bcj35qlGQ3UpZF5cpABmST0y2JoaUaxfrAiAOhvB1YUB7W9PlJJk4m9BhtMb8atpLB+0zgb58L+A9Jw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60060,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtudYCRA9TVsSAnZWagAAVqkP/jeJzbwQG3fiTQ8oO6+f\ndRq+M0CVQS5AhI+cAIL6/lnjHQViS7QeEYRReleK87BLzGqglwKSgMQjh6uh\nRib3QAKAZ8o6f49UlkaodtfiPMOFJ6H20Zk3qHOB37Mg/46w1IgYgySZzAsJ\nLVeFDRDtNgz/9l1X2U1EBk17vfeRC5rRBf7zxCRO5xOk1fuy8MTnYaWWf0Kc\ny3MGG2cyKBnuLKJ2S/3uaSUMNkQWXgTVPUDxipi5PlGWKVdf7V6LTDprl0i4\nAu+nfUgB1TyN6WWu3AGcRThnnVxwhMKRie0aRNGhRtGtR5/zBq67qRGfmODO\nfT7R0hOddakjKUw24costIbtwpWg7dnKjhG2NN4alQwwknp9uBxGXy0LoWLF\nhnSw86mkiTYgaur9Z0p4BDN+9dqMjzwH0V4zt+XRGDZoO65dN3aGZ37CSz1H\ncl0wjra8QOcBU3QeuI6s080zrzLtWdHt34T2iJRHvBpRRR5+T1D1EWTI3UBb\nFMGhX+4rFKsqkqva72XuMTGyD1w8d5wNwNwk1qDfeayHxT0Q/vpRHExXjUKL\nOcTSrg7GBMtyTOozZCQn58u7w5GnjtuVxS4M7K3AxflLzf5/qnNnQOXVkFw8\nJoCCegmK/xt+4DlrQMuyL+VouOiLN13SwCOvJ9mNyM3QGGL+BwKrLrWSx0lC\n2NJI\r\n=EbsE\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"25903783dc5f11afba98e298f2cfad87dde22b56","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.19.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-e828954-1622599460736_1622599512253_0.8170713120855377","host":"s3://npm-registry-packages"}},"1.0.1-canary-82aa02d-1622622027987":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-82aa02d-1622622027987","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-82aa02d-1622622027987","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"cf7587bc7173f0ec793d5eba75f922100091a56a","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-82aa02d-1622622027987.tgz","fileCount":8,"integrity":"sha512-zDT0o3+OV5h+vEXSyCM/BOBTKAF6DXgb0ekLVbpa+fZuJVRWVJCwI1C/lMogbks8SjfvwK+z6PNebVhjn+YxSw==","signatures":[{"sig":"MEYCIQCpL3cdaSrW0MTS47rNtSvON852hFJEYg/jHt/bReOw5QIhANr2GheIqsIUq9yOhqnKGG1O9Xq7ZlQs3JYPvdtN3yg4","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtz97CRA9TVsSAnZWagAAsqQP/0dYDRJIGuIMSkf5ct1f\nGwLF3pFEFe6V0BpOAEbcoTAe1z+hAeJ41ca3ayod7BazwWzjPBKXTTfKatkR\nmL0vENUHYueUZPHtAHkqVzHFSdmnSs2UKr4QVcSnYbVD9/5dJvn5PPOQF7Wv\nXYgrAerzYivRDMCQsBqCM1paV43h6K0AEKdihXoWaW7WZZQj0bSAIc9TBZO3\nNY+UqaekptlM4SvR95QzkqyoHxiFX34JA57bwuHzqVAChJO/9gAgj8X0Hddl\nvCeh+HYMST9IIVzi8DAv6AO12yhFbbg7ZrMlLVPCOPkmySqmwuBN546dAo7A\nBxYPGeOa9r2226gnd0XkNZBKY2wx1xdhhMbleXcXn1Vroytw8f/3xNO0OL3C\n4kU02ESkhwYmiUTNcCIqdxHPRf9r7rOe+aD4Pea9wQH5DpH6eDTRav/t241I\nYKrtAwArIKPJ/Xb3zNhh/fWg3/1cDzh1wINlr8HUVR9u0s7Y68K1Ixu6Tra+\n5FGADxkuCIjNP93fUP8Qf0RJNBj7NnMZif4PsXZPXFJVo5ueRoCWF11T16GW\nVZO1Sb5obwUjAHpQ9wia80blnzi7Gh8nF2qKubqQZCYSIkO9xiBTsQIIfzCD\nTrafR7p8m+/ULe8xEsL9ctnkJpBgWTKtxTX3QXYIOrfgnP5gaMm0nfw5/iAl\nMRZQ\r\n=fRrq\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4a10ed24947a1a317c15b8e8e95f93f7dd1f3f60","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.1.3","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-82aa02d-1622622027987_1622622074492_0.5185097695601397","host":"s3://npm-registry-packages"}},"1.0.1-canary-a13c986-1622626694650":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-a13c986-1622626694650","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-a13c986-1622626694650","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c38ee313d4fd19f25c6efac9c3ca3b4f26cf7177","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-a13c986-1622626694650.tgz","fileCount":8,"integrity":"sha512-dM13d3wWw0HCQcvvwoQ9bOi0hf+oSzo4SHNf0qc1Np7qy7ED+HzYpiUgrX6B2i0GpguRzqEvRSgKJFq96IxE0A==","signatures":[{"sig":"MEUCIQDj0WsMtsn03ikDiPiyg0XfDviIxWkiem2IZ11numB7fgIgQNNJI0CZm407DST1Yc250UX6VFrBb6NDtqoJHcKJK/A=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgt1M1CRA9TVsSAnZWagAAeaQP/0PVPms4PkpB+fX4dzjv\n4+ixO1GHK4aOgGR8oPXfPobJRdvLs1/leZXDkQR+A4joqQ5SHA8NTmx/ZdyJ\nYNWlxZhtes8tXnhHoqNIc6frZFjcKi7nWW3r8iGdCiA7tP7q+4vIdgRn2qj3\n0/iWVt5jpK9Y33WGiKTYgPsA3s3nDd4irigpce5qNncmOh3iMbMqzTtPXUG4\nIPhhq3iciZMIDiRKYUTccfW3+TYRGvzl2shi+PN3gsD8mgaaHG8KdRbEpSO3\nY+rGG+5lMCgnmtfUgy6J97u0Q/B45Tx0B4zN2EyaOi+lTW0Hq1Q+uUSxbG6a\n2AmEor4qH84B2wpRwSF0KhW5tkfKU85fMgdFRdLauKk09wwhE5iEGOQwAXkU\njgJ2vaNKZaaXJDpK1TG1oa3w6ZQAUn8nmEczgX3BiwVdMGpuyGVoHPsZNX4j\nYcvvOJ/yjB8WiVpOgnENJpmEzqHm8pTQgN9T94Hb2iBhLjhtednMRTPlfRme\ntyCRvdd69meV2+pToAIMwFIPuaMOZP8JVZ4H87EkTyd10mAYDBMAQKjxHeOr\nbRwyYLzNOu/U+ZalLcZzgB7pUB7wN6zxbt0ru4/znvnjk+zxb6KrD1GgnSNu\nnpK7mnMIezfF2uqVSCs1pCA7A6pLRsIJDO8q6C/XQgH25jwbe9kqN/83c5PD\nxExl\r\n=7L88\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bd3e8cda63d5257967fa8f056aedbcb3acdfa20b","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-a13c986-1622626694650_1622627124885_0.19957688530697104","host":"s3://npm-registry-packages"}},"1.0.1-canary-a13c986-1622626732673":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-a13c986-1622626732673","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-a13c986-1622626732673","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"230f68cc8968b7f878cc02c24b6d0025ef80d883","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-a13c986-1622626732673.tgz","fileCount":8,"integrity":"sha512-bbtEx7rBNcQSu0no5s/KvIXlfvPNs1v6GYlFg/O16zv+E8Nr/U1e+ZuorsZ1kYf/NM8dpouIQusQJQ4yEoWBuw==","signatures":[{"sig":"MEUCIEeec3SS9HJAodkEkSNdRGNEm6QJpoT9BYG7Z+SOpeWeAiEAsNeajBH/K3jCRVH8cc4MDKDqUP/M/Ro9QYBCdgcrOtg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgt1NSCRA9TVsSAnZWagAAlX4P/0WiS1ekVmrwT0/M/wqt\ny/aX6qpuofAef4rOsOJIX6hdDxOIDG6oINmHlS9B8fbcomYmHF8EOvRzlkN2\nQOfXZjTuNsTp8xMNxtdRQW0ijwq1dvdtXYNV3amegmXCJyQX2DVUjAq1uTeV\n/kCyeL7Nr8jWfn46EgYMxmItFkFX4gMtiDeaQrnELVSAKrAxatmiU9Q6im4f\nnk3ivQXKxJiWwMrppIzEOCRbncCmF8jzl36ItYVK4K3a1Mmyq1gAggcox8dT\nSBlRjoVle+xv7hDPcvLoww5a7UX6kHIrheWh0YzkGKSga8L017dgWqsYAoF2\n7D6gxS3M5hYkSwZWbeoVyd5Sz1N6eZ4hH7BxbNUki5BRRfYupXKUbbgNBY2x\n6TUcO9cVa8OHS1Dw2qaczqkjj+jNxRf1uCWi6jnk1qEUihkP6zYJCQdtsXdB\nKc08KynGjqvdpM4OmsO3OqhMO7qNITivQt0JqLMLnAWGS9i1cdo9CFgQQvIB\nTiV+9L+lVQIv340Q6F309plTA5YT0HNocbNIsdGQjf5+lO8/xKsiogAPWkO9\neJPBYFcBfblu7k0Cg+IfpVzeSdcR50AHkDzYMsX27v6EeoyGs9n1gK0uc7vw\nLI1Zh/Q2fS91B6A9/rEAFdAaG6EI3uZjMa5njIG/tFBcSy04OZc75OHMWUlz\nlUYc\r\n=DOy/\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bd3e8cda63d5257967fa8f056aedbcb3acdfa20b","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-a13c986-1622626732673_1622627154562_0.8856337765440352","host":"s3://npm-registry-packages"}},"1.0.1-canary-c299010-1622685700266":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-c299010-1622685700266","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-c299010-1622685700266","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b306b9e7199e1dff48a789fe11f1b78a698cea37","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-c299010-1622685700266.tgz","fileCount":8,"integrity":"sha512-IUuBYIdFc1U7gHd4XgcnAUhB/LQS9NhVaiwQPuSlcNJ9krDL8KS9OkiOnN39NIPxJd+qPZIkCPgzP8euGJWPTg==","signatures":[{"sig":"MEUCIQDorDaP+doQJW+Cp4SPYQrzIS6oYuODff75kXy8UBVR3AIgUMlMIUnaWZYVIfw36mHYWh2kYxYYIXXs9RdWuPwzubQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguDg3CRA9TVsSAnZWagAAZlMQAJmSWeR3fYNG6I8ewZIb\n/ISRpZx7e2Iu5/i3yewHnyUoBUm0y/v3O1RUFiM5Ds26lpSPEsHD+p6oqA6z\nK8Ije3pq/MTmuz7JE46elRCGaYmQQWJ9q9JhSalNMyGODZk43ID3oqE5y0zY\n1s0gl6yI80j3ZwLnIwSHMQ/ZLakqdmWmzZdqzKRVOVNbL/Cyn9gKrFX9NLpc\nUkQATxxwIYmDwJy9B3jiknF1a4mj51HMurxhWyrGfzjUCpNezXLVvnn+edNb\nj8UIo8RWX70g8qGU2Ag+bYth/fAaUsZo9ftn+bSV/LQ6oZgyLUSz/Fchdfa7\nBEQXHIhqCuZWc4q/gfMJ7mTTvTykDNcb6bzh8sCvwmYGnJACQTx7i0kUOOoX\nc4oSp7Akb6BQOrZ3FGMCFk10uEAK9ywE6DBkeGFBnJi6TRuA1bm+xFR/xChX\nbgyB1V3MftENw7gUkmLpbcmrNQJAJV/yXHnUA9jEx41u3CNKxdv1M8MwPdpz\nou1hcXgW2Sne35MIBJRKT8tZUqScsWxJKzw/Cb07lwIx+BnwTu/vzDhq20xp\nBgclbbSqOgpNQ2+M0ZbqzsnO5oVmVdSTMF7ERR9x8/KRR834sWDV8g+3oERs\npE1j1W733usOpf6j4qjy972SKqIi1TY7Zly/AxyVUSgpUAIC5n/aD79kIY5E\n+Ts3\r\n=6Eo+\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ad06191bef607ea36054d40fbcbf3cb332849412","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-c299010-1622685700266_1622685751018_0.17524244965737257","host":"s3://npm-registry-packages"}},"1.0.1-canary-c299010-1622685695358":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-c299010-1622685695358","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-c299010-1622685695358","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"03569bd33c9be3d006805e6e87230d5cf57846fd","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-c299010-1622685695358.tgz","fileCount":8,"integrity":"sha512-Qu2uQUr53/ePuStk4Xa4Go6y0bcRyVeEaFl1m3DpCNX87zgvvwMw2ZvMtl3RsmcRo773tJdBQwElAyLmqApE9g==","signatures":[{"sig":"MEYCIQD9r+CE9v5X/D05+0ka7iEvu0/47VmQGvrDf10+fjZ6qQIhAKmyC92PU0r1gReBweX5wbBOR6WIR7ZZrYEjwNwD4d9h","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguDhICRA9TVsSAnZWagAAlDAP/3G3iALqE8NKHEk4jo8n\nFWgP33cknL9ua31KzS3XkhVmXRyrmThWfiMpS6rz5ooxCtZxLPZi8U8RiXRZ\nCmXzsM2CGZ48v5351ktj8iXRYZD5GB9LghnlpLlHVhsPfig/hHA5U55TCucA\nYWi+7RD+06olDpHWqTPj4QKXpjKoenX4rhYnkUKkqyNL6K1F6b9eAS1bJqrw\nlKkStmOhK/Iw6q0aDYmrfd2c9wZnBX2PcFokKlhQUxWrIICdl2llAL86DzPU\ngMkauKfoQsWYtAkn4Ivjs1s5oIeVGTG+AUwaRKOb5Zr3G8M1EpYeUWeQ846T\nMfvbZ2+OJml0ovYHvigO/cCaf0nNV1cCBBkczYCBZEc3I7+rfIZinleTQwx0\nRZDRRPrt7PXNSk/y1wEvouFogwGyCuGMa0aNWW5FiUvbS4mFHh9SPI+6yyRV\neeW8WiAFaW3DsBnINm9aofF/jsCrx5CacH0CJQLwsZ6r6L1nXD7J36YQV1X8\ncwToNGYq+4r7bnfttMa/PwEwiFNJ+tP4M7Cefi2nWoiRQUWEWXySR9nGH3lz\nflL/czW4aL5spbAqYoFlG8UDp7xQ8NqhPBi2Wez9mLz1yb7kxaziBhAjZVYu\nlN/TeAOwF3yw95iRV1h2IOGbTzDNH6FlxidZP2cBXmV3wQjEAxxt8MgqVjM7\nxrHF\r\n=2gJc\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9b9dacc76772f12cb3dd4e3922ebc7e2e248fa93","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-c299010-1622685695358_1622685767987_0.2018132404648607","host":"s3://npm-registry-packages"}},"1.0.1-canary-c299010-1622685721681":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-c299010-1622685721681","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-c299010-1622685721681","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"9e8db6256daf1fc1f8e1691c331a9c985163003e","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-c299010-1622685721681.tgz","fileCount":8,"integrity":"sha512-Uuy+TP760pDAThoQUJ5to2bCEIpcFJc258uRbvOZnrkhpFvlS4alNrJg1yI/ZtexKQX/zxshx9eyMm3yL/X01w==","signatures":[{"sig":"MEUCIQClBild6QSeJ4Us6Y4Y6bL+WXsWJtijkR0yW3ra0Wy/+gIgaS31iZC9oh3SkhLUCv7K19VQBgOhyvyscJl9cGu66xk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguDhaCRA9TVsSAnZWagAAyY4QAJYhegdd34Yqv3Hu0XEN\ngEjMidL2mwNg3BZnXq6O2DX+dEc5IfU1EZtbA97rsr394wYTtGyLaf0uigFu\nTrD4MMOKx85wjyQeMeLrI0ox8H1KPtSpUZgu0kLeQrJ+esrxZtqyNqBpdhYc\nqDfOj4NbjwRaun+7mIuuwkQ/SeTd0sGdkIkB/df6etxYCC8QgXm55w3tUu3n\n+tgbasnGAua7BjGItka38NJ4hH64iAdFNJELkCI12BdQgZKJ65ydFVm9olS6\noapEREZtaXWkEYPVOAmS9b9j3yVnETW1c6dh1eNpfAhuY2IaKeJc3dVN2x6F\nez76yGc4Id7diZJhxKASeOnq91JR+xOAtIpkl3bpkOgbmRb25IBu2+h3hdzZ\nU/hE/d0nHyLnviniRkQle46NV1G7axhJ5ckOp88PXF/2o+r3+8iY1Cj8jxSL\nqru/7OBSEdE8dd+oJnKnulxvCAM0wWpJ2M5MRYNiantFginxQXQ/HSVEZpuH\nMXncnc0ZOEQwteBIIOZ9cPtaiQaPpPXnK76vKZHLiP0ayLRiOz9mc/XVXCMZ\ncJPGUeK/0vPXt2eJTiRwXmDk7wpKG+U1ACnFFegAXbkEJNqhnTf0DxH2zaWw\nriSuswaT3RJtj2HBe+PyH+Ngs9gwrJNM6UqPqfJzc7CNA0mVweUtISKWwwYA\nrk3Y\r\n=Xmik\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"f30c25df80136cd8583f64ab44fbcfc64aac8262","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-c299010-1622685721681_1622685786745_0.003928561322568802","host":"s3://npm-registry-packages"}},"1.0.1-canary-c299010-1622685736571":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-c299010-1622685736571","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-c299010-1622685736571","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"180066928c35a5e5b01ee964cadc4ee498e7a122","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-c299010-1622685736571.tgz","fileCount":8,"integrity":"sha512-GnJ9bEufw9uZJ2SUkeu6iAwEZa7Cl72n6FCo/8tBdmtscMP284faiFAQcDbQz9Ct/Su8syjNx5MbdCguPR6Ahw==","signatures":[{"sig":"MEUCIAz5p9E2/IHwbQB2LQPA7IjsdHFuKAz1kQ5wj6S0G5sFAiEAhplmeOHniupSB6SE3mz51pM4d6s78WfRs6uW+l7qWAY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguDhhCRA9TVsSAnZWagAAi8wQAJ8oBWubj/rPwhBOdk6p\nKoJvvtTZizwF+84n6IdmwSnXN+pSmA2oxYw5eda4at0NhAZbsasui94GojV0\nYrTNoeFjEpVM9/SAgNETo8hfaTQPHpQoTVtQRnMiRNM30P/bsyCZirzr044+\nbfsTG1Ygtv6I1ouE0c8HAliUCDNf44uGa5KvPNBxwbU1rrPJfH/uqccJpn5r\nbVQkABdAJFYHzrw4reZBGUapvqVl48JZqCj+YfgWAZGnqlq8BZUImLrUq2PG\n/UsKo+Zkhn/Spdb3K2826t4sLruAe+3tHK93ZQaiUV1Q3aig1gtcGWyMTm/+\nHcyyW+v2DtTxR5aGU6xMaKe3xQorVbeQ4dWkBx/ZyYoF9BzjbC13+E+7SO0d\nao7jlowaUOSg6Pnmbig5ZgJQ23iO+wK2yLbB84uedVzP1ngRI3a80ZccNVs/\n+dTp1B/ObVeuI//Fbykcv3Kf0oRQbVEluno/iktpG4XhjQimGxi6OsJSCLim\n8nNptpYzkvq8QIoHIaEoNlCHCHn1AxsqD2yK+z8FXBQmYsVyVpt55iVQ52D6\nGw1429s80g3X3aNpp5AwkK22SQbwT4aWZwd0lE29P0u0sIpqPGZdJkfNxaPi\nIf1QgumYxQRIO+n7zCWh5Qp4k9A2lw0aKVXuTm2xcLGveeBHOchN3n7AiIZW\nqHEG\r\n=1afV\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ac0ffc63a8923739959c435d1e3b7ac59cfc0a6e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-c299010-1622685736571_1622685792901_0.6824826006588365","host":"s3://npm-registry-packages"}},"1.0.1-canary-c299010-1622685713560":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-c299010-1622685713560","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-c299010-1622685713560","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"38be20785df78a850d0fc2e7ff2e974713ea78ed","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-c299010-1622685713560.tgz","fileCount":8,"integrity":"sha512-dL9f/oNEm43dGUtHg29Mz+t6O0UrLFXac3UasM9WqaHDw6FI3THSOCO331pTlPtz1MU8PG06jpvfxfpm/kq4OQ==","signatures":[{"sig":"MEUCIF0UzHYqUFVwHUY2hgMyQe5ZSdiWyIT9U6Ydgg7rQbWuAiEArxDg7qfuk9Gu/O7km0CvhBSzTp78WWftOAr5mMV9LLI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguDh7CRA9TVsSAnZWagAAzvIQAKJZpY3MLReUreZ9vBDx\nnWOycwzvTi8tYeJQj0cbmRLLe7Fote8JCZXugjIV8n79+d/V2OZa1D4bvYFx\n7/UTO6zd+2OYmocqZbiHZ10vmZKFT0fbjWS++D8j1c8sOUoqy3QBm3vWoMJD\njhNdzit4/qfJODHG6OVLvz0OGwU7pTWhNL618iSTkg3mNS0ZUEMcKUlYT7nU\nIBMoEhNskkz66BCnfDw3qk7woda9I4BgjUc3JiVSTpIB7GvfVeTU+LTOezMc\nVJWUoSxmxAUX/znsNKZMl8UYI+jCsl5ayV9IT3ySSKh2eNug6AWyduZ9fKvG\n7wsOekDb93axM026vYoPobtp6YVe8Ua+G1pG5xoGTfhvIZW21vrUKlLFkJ36\nHCqT/V0DMGadp8HEYNDL8/KcP6nVnwCKxcfSKikulnumZHTE68lBCYApBfHp\nRenNJfXdYPeeMFLr8z9AeRuj6E5bhSV1DnHPfxBwW+AnvMsO5aQ8y6taP+4z\nUFg97cjyyXnZCKUe3zrT4NKju9yGwjqXVDCHEhMolm1pbZhx7sRxzluYnh3b\nhYkNfEDRrnuaYCYXDOzoiO7B1EfDYH4uipZapeLPaLDPTe5IxpUEXovaHiF/\nhl3zZJLfqoGmZnp1Iyfekj0sGsOReWerFXYs8jI4y1n5MSJn80+WdQD6hrIZ\nsCya\r\n=LgMh\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"00e45ecc42a34c33507fa9930e175d159a5a9e65","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-c299010-1622685713560_1622685818931_0.20860511322888753","host":"s3://npm-registry-packages"}},"1.0.1-canary-c89b970-1622710257757":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-c89b970-1622710257757","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-c89b970-1622710257757","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7f8bd73b03c0fd4a063d920e0ac92ef9a73e1e3b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-c89b970-1622710257757.tgz","fileCount":8,"integrity":"sha512-jPgtGFZZnX3ITU+w/Wqe/opg9/U6i689/paY2KDTWT4AV190mV+hRWgBZwNIWWEl857dEK5zL9Ywf1HoLaQ1XQ==","signatures":[{"sig":"MEQCIGuSJA+1rACMXKpzQukYhsInNjbpEQkxqhkxurx+UWLpAiB/yZOcaL+sXPCMglB84pN79QDskoohVAAROS2QDZhvqA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguJgtCRA9TVsSAnZWagAAtzMP/Ro8htqmAv/Tynm4lHtm\nONVwZD+81NyyVWFidGVtpqG0JyxtcduIDFqEw2O9LlFUBzoYf/1b2Sb2Sa85\nBD9wt3HORZ0Gs07XnjFyzCtcuDx2FZmfO9eWNVc8sxc07WKreqKMa1vmoyeA\nHSHLSHSfGvRAEtZuddXUdnHHGjzc+aLt9HkIprygT0UShuiS/loHaDPSZ14G\n2oseCpAGkNMSsWlE5wvORwESDUFHeSmmhtotLesj8eZq05mES6JGMi9H3mUK\nDDGgujQJX48tFq8djKT0zIAgRJ6e2NqhVtv+ToNjslNO47zDNzQZ/HmkUqax\nN8Ktn5mWPMCOALHwwLw11dIph3PWAuBY/PkHsAnPb6m4qSVgxxDkTR8VMi/i\n6RCQXU9Lu37rwIj3bryjBhLvdpckb0X7k0wv4P+LfD2/mdNZmIE9F4FMZxMV\nq2WUWU71eHCnqEbana9qIcG1zcPIz0pRN3Vs4PWNKPAo/EiTnq5SERgmhC2s\n/peRY+O96P8bm9J94LCfCD6RzZD23wZY9/QA5b1AWx+OSNe9+FIWpsBkK4Is\nLUizHCegAnjz4dwVS4Rc7ZBBxc1ZeNaJSdMz43g15toOgt1GoSOYR3y0kMiS\npXfVV5fVHqy5np2QzQ74LC1z8QxW4GN1KiLVrwa7KEHJ5tlcJfI2TwETLH+d\nfFq8\r\n=mIRh\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"caa16a5891c85a42313b0268df692db61650efa3","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.29.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-c89b970-1622710257757_1622710317801_0.6697109139449682","host":"s3://npm-registry-packages"}},"1.0.1-canary-c89b970-1622710260498":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-c89b970-1622710260498","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-c89b970-1622710260498","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7c2b5a5a3104b49061989fff80add62b72433179","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-c89b970-1622710260498.tgz","fileCount":8,"integrity":"sha512-1pTuGdrW2/MbECksaspc3iupiP/UgGgQQuzfz17l2pjJSBZzqZbdjvY8x+lYcOEYoMOkShsZnQemat0VhscGoA==","signatures":[{"sig":"MEQCICf34Cy76+W9RFpfmrmKN/hIpM3rXlG7RwtZqPlRnHRMAiBr3kqh8VRh4AYSDj/Ca3KUhKLGSIWmJ8tmk4DU2/lDnA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguJqWCRA9TVsSAnZWagAAAk8P/3Ev1kn/v2QUktc0Umlq\n0z9eYZlh/AiljTahUvaqkoTSdOoLnGtcC3Iqv6vFtNYi4iIiT722sWoyzmFA\n7o2Vjq1FYLXQietwLZpDzYzI9dUAUdhDzb8dr0gE5yf0H36u50PuIEA1RW5J\njpxD8O4xUekJb3RoRr53PkYlamBbqo5ozXC584DcGsBRv9fGneEljBv/+Avf\nuBb+fzH+tSMjsE56TxtkoyO7dk37ChfZOqoG2cjagEskI+FnYQp9uvjYJj1e\n54yjCsSbL4H8A5rK/eceteWqN5tuSI382LrHfXIyVHmmbk9d8AwTMehEzYPw\nR/X9MWXrpg/VyN1AS5HVX10PyVv7V+CAmJYRLuPPZ5jK55JV1r6rRgiETY8j\nFAtcLH9u7WcbtGgdeM2wVgaz5iGWZCXq5cVEnZwkalTrriDLOyB0AlUGuJVD\naygp+XiDJDWgJ8ZYbmZ+z7n3fJ8Qz5qt/dAUr+FPoN30YZkuLJ4HBBV918A5\nRaC7ev9KWIG33ylQhq8qdTlgASIT8YSFG70N67moO+sMwIdtTr4WRfgJo/ZH\nLMDXIgnS1dazKkLnDKxcdaPEwsLBlhvVWbFfRo0QtOOK/gQoyH8k+z3Hakkk\nWLUY0wmh8xY+otKezDluC7KZT0DK1qEbSpPN5p+QkLrpBkFi4HQvCxjuWVHv\n0IL0\r\n=b0Zy\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b899cd8250874ae5f535c2505bd39cec9928d0d0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-c89b970-1622710260498_1622710934754_0.07946007714195535","host":"s3://npm-registry-packages"}},"1.0.1-canary-492609d-1622711125483":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-492609d-1622711125483","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-492609d-1622711125483","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"91be25d60cf1a57347736c0cfcceff849ae5f041","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-492609d-1622711125483.tgz","fileCount":8,"integrity":"sha512-tEBea01D8sDJiMj+dix8CzPapVzRjaRFE9tjBqz0AiVZorlyKO68fBlpJNOtiLAmKay1doPyeb9JMrbbUunT+A==","signatures":[{"sig":"MEYCIQCQJkgan/WZHxXF6OIxkHRA1Pj8EMZX0ruZh72GexPDwwIhALpwXTNyl2UPa0X5mMmDSrmg6+aGMtZTj/9DXd53+fSJ","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguJuRCRA9TVsSAnZWagAAzAIQAIPW0jgvUQW6CtzJ+Q7D\nVuTEouu9r5sEPk/wjpYyaLmehRbTYMYpEw0DYGzb0hy3dXKky1rAOVyu+qnV\ntOufRxvC/YMOW+x6wX2P4GXIVL2JJlgS5MGKaHFoRVZmqLUCIr1XDheGLhjc\n7z5RBhPWydghyAIRdiu5BTNTuFu5xEJWQKL0YvC6L1DgF4voes+1dCPk5MvF\novYj0ISJucJTN6xWbejjiNDaWSra6TBTy2iP5TN22eTqh0+HAmXheEJGEC4Y\noFmmgexpijst2v4JGXOwHhXgHzQcOGx0LyjTpfsgGfdiYMgrCB8k4HxAoJ0k\nbAt98H2gyyi2hOw8yRLwZSypkQ4xSmPdXsJim8/IxuwbFIN4aHKPVqFQF1AS\nyrD7p9ztLrYNYB27Vq56w/ea+zrTevoPJK/kAKFLNoI/2HCp0JKPZAiz3nWR\nzfPJGYDZt4he3gmPiLASkaIthU+VSLKYVTy76MkoMYV2tl6b/KwI8MKCfvoT\n3ByBGpt/W7aJrS4/tayGUHKagMfx4gwWO9BVBIGpMeBNHUc3U56IpQZ1RVFX\nHm7hvIJUfT63wZtoIwlTJ2KDgQbKE/SG3k14oxkIA6wGci/Kzg/xS9M6BUh0\nvCMEQUtCp0iuVPuQMTSXOeLaXDD64YXdZGT042siOl7AHxchTWMu467D6AnI\nJGqp\r\n=ph/D\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ff3bdf6342d6f9d45b563710767a142be0c91ef1","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-492609d-1622711125483_1622711185194_0.21090919677323527","host":"s3://npm-registry-packages"}},"1.0.1-canary-492609d-1622711126166":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-492609d-1622711126166","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-492609d-1622711126166","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"6fa430b25a3984abda803d73a00ca9a3f95de0de","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-492609d-1622711126166.tgz","fileCount":8,"integrity":"sha512-BL7HZSW8tB8aq36IduZ5rumGjfyEBUdybSpdvgl25ouox4oiDaYTm9Ylzj2PlovTjw45LqO33T8b7C3306LAmA==","signatures":[{"sig":"MEQCIG4j3fSHUpVvEhcqUyO4Cea3JB69ARO1JHaE2U/0xh0bAiBj0Oywnqa93JGm9XRZWEInK8MQODTaqavx5L0vv7NlJg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguJuWCRA9TVsSAnZWagAACLsQAIasDxHpRR6oqDeSkmk9\nIU74ZyyowyaB6LctFjvT9lAy4w5BIV2e1g2h+B+kEdNfpxFjKs20lMK097uh\njKd8vyHHB40ejoCIEvOO1JXu0A1cB0kXfMTTOEvg02FT+BQopNWgcMD3uxRk\nF9JMEyPmaRVDWHrvWjMZ3aHmqygzwAQj33g2kp2IZqpOfCgtEqq6sMTcpRT7\n+SR3Gztl44nGIy4/dFfpeJS7Z8vkLkYGE+v+6I8wyW55xvBb71nIRrKwnv41\n8me9iO2DlOruJZgNCZv4bB9rieS3BCdv6p5w+AOX1f08RF2Ch3qULbhQlEk5\n6oMKrThZBqT/3TK0+xv9LrmwVNxt4qAERn9ZdU5Om4KDQlCf2Vf7kKhnxh1x\n7bAdTSZ71Fn4QZARu0sGuLZdpAvcrqiz8CAnGY3cHAJJUZeIpKdsL9eDSRxj\nNRf42uYKyIoFqPgyVD0tFuhVDxGSZpw54GYvH+q6d2KdiCVIr+NjDqgO7sCn\nhIY5+xgfL/ee2w9c1ltDbjVnQ1kQXp4bw/qtAyTpv+Ur0WVqH4HGNaW4WdHB\nCkTdX+xImoupnjvWGdV8Qi/TP5VGtqjVsfUDWpuUxSgQ4c3O8FZeiboVl17C\nI7LGEl9xPoBMnpMInMgixrQIyd+oDuA08EEPsn4RVsBUydRnSBkQuF0zOZ05\n1dYO\r\n=y6Qt\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"d32e0c0a82b83ddc7d363288c5080937d0a20911","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-492609d-1622711126166_1622711189932_0.03746284448488435","host":"s3://npm-registry-packages"}},"1.0.1-canary-492609d-1622711128865":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-492609d-1622711128865","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-492609d-1622711128865","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1e7fc48694709dbd26b3d980be6c6b6f932d98c7","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-492609d-1622711128865.tgz","fileCount":8,"integrity":"sha512-qicCx79qV1ODruGqKTg70KIhb7ecdjliZZMPNTg4HZd66fdYQxgRHa+2kIBSmtgtFi5EPaJCN4fdxf+5QvzXdQ==","signatures":[{"sig":"MEQCIAwKy2RxlJZ1stlt+Y2nON9W6+xCzNE+6wVEx/Tga9V5AiAp/wCZw6cNA3GYXZKPwTvM3xTCf8w74+7Yk11uTMp1kg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguJubCRA9TVsSAnZWagAAo1UQAIbaYfMSmX9Ck4u33UKb\nSGj/WpX7zXl65KgMVgIa07uqHUp9buLuNLe1jrVWryR+Q6eJAHdwj9iFe2ww\n1C3woNGUh6OmLOt1HZBVMrVOAi/6kDcwAOWCj5WGotxAZwLJ71u8sQP0jN3L\nSjVqoLEep9+8mNW4qo2CAkD0QnC/voBNG7H6RxnSPnUL3V4p6UUec5ydN9kr\n0BB0L1uYkqikPI6SjqxUwxSvH4nZF/YX/QFMUQtUAkXBmyerrnhS8yRlndmr\nMxDdHgsWo2Pqlh0kJQ/o0zWjUeTA5myZmiUepyd7cg1DKI5Hy2PXeIwKSd0l\n0gbFOnIM2UzOPevg5iVg8OHFaqTiHsorykieQ2w3cQj2srhxR/wkOSE0iYxP\nIAf/RJzVvQcW/vRNi8AtR/NeO/eXsHdED48A1cOnELaofXHnFJMVRLBAb135\nJXT4Yn3aoGtitx6TVSnwFZng8o0zRZBPA9Rn3GVC4jBNLdh5cmSldwGLv/zs\nIlXJ5pkeVvNHX5JTsR39M+qTV8B3FW+lSOhh5F8gAmMQWeP8cTHpfD52zPf0\nlO1EsWJN3e+nmIYdTdGnxx1ORtfwTHdFcsXiFDSVcrCWJOv9QBLeZE1o+Ww4\naqsFUvT/xAjOPAWSS6JCdUkDeugaRf4ATNUhtMq1fqEmDFfNzBtgUSxK2mjh\nYIPb\r\n=pEaj\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"a384bec9e4ba63ee1de6e72d88492426c2d8ce05","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^16.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-492609d-1622711128865_1622711195661_0.1946663957636452","host":"s3://npm-registry-packages"}},"1.0.1-canary-37f0dc6-1622772106711":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-37f0dc6-1622772106711","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-37f0dc6-1622772106711","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"04a6046dedf3bb2adb9391df5d5ce8bc2d9c015f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-37f0dc6-1622772106711.tgz","fileCount":8,"integrity":"sha512-a5oYMUoR7cmVr3Bh2wQz2zcKEUA/mh2EyWCa4idXnOxVT78EF86rUpYv7O/tt+SiXR+UA56sfpxtysYvZIaenw==","signatures":[{"sig":"MEUCIHhjI+pi3bMjkB50hyPa4oV4MU4369bqW7EUO/Gg56DjAiEArX9CaqkCZoFewJvR/v28uqxGlNWba9BHKalm0eQWYM4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguYnJCRA9TVsSAnZWagAAqMYP/2LDmnCtMbi5HBSxiSRf\nVXoxYQ2D/L6OiDmF9TniDGpfWWJ8P4ZaJUgipbYWzMHhrnmKptSIErxNNqr2\nJkQ19FyI+4NFsKp2of9DjKzfvZ4Dm7p/todyQfltkOkLTbCQBxIAs4kBV9Wz\nNuB+WCWf5gYRCBKIHUpBNFng3wnihYbJPCEnHiBb0hOTtd4uw40mPLPAIfSd\nG8yCPJR0a5kTXvWLu8GD1gsmOU2I3rDnMmPm6toV8vI0W7pN+mbwXOp4uNCw\ngIGv5FTDYn01rWUfYuL/iaTpSKGvL2t2mSAAcpRQ7AzUVzVbKX0+Tt2dma0W\nrpNTv6t/YC6P0QfHYyHYu7naP0kMpNF4K9r2FsSDVP6NBmqMK8RAjYRWdVn0\nNWAaki0td1Z4Me9GMaX8aSnNd9hUXl3/OE+rJrJC6Zz96grqOsIKM7KqMkix\ntyIomG6HtOu/mmFLwLSvzRpW6NVQkK1HYvfJ9/bDxAaaR78Y+D4gN6Qgotse\nlwQ7g9VoNKFrIqtMlx4npyrcs+Ktu9B+r0cDwkgktOWEcookp4BzAM+ExL4h\nZWa9l++ZmpRdClK/8nleS05lvyBHXotgwSAzNGx9JSYdCV2CJlXar05vRvff\nq8O+9VIjjRWklpc1fdKKwdTIqckt8Gbb/LFed6qvXNNk5LXd1mQiNlvTBYCM\nZika\r\n=rDL4\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"64df07013589e2c347f387cdef5fc93110eaa2d3","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-37f0dc6-1622772106711_1622772168825_0.332050694525591","host":"s3://npm-registry-packages"}},"1.0.1-canary-37f0dc6-1622772118990":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-37f0dc6-1622772118990","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-37f0dc6-1622772118990","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b6a1837395b62814562657502effcf1fedbd2abb","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-37f0dc6-1622772118990.tgz","fileCount":8,"integrity":"sha512-/fNn9tHBxHcpK2wpGwLfnCbgeWsrM9OxAwACFCXVRdls2vO039uDP+/q8+Gt7uCtRmAT0fwDLr493ElRFfZ9Rg==","signatures":[{"sig":"MEUCIQDFqNh2/hMwRyTc60ukl5gBt3bXx0uJkn1d+t5YP4hZUgIgGs+j0/jkf7ERKsqgtH6a9azJ5INCf2fru/U4Bo5dPSU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguYnZCRA9TVsSAnZWagAApmoQAJkGoXmzF1LF+DULS6YS\n+E5wUHyngz6JBhs9bANqD8WICKWgPP3D0O4GgAuxLy7H1cngud6FnRGQHujJ\ntUFN4G0DpyevwkRP1KsRNrN82yvVP/Ej9pQgwPZhoE6hCX9JvG9LSrBWZQ/r\nfi2/5pixwi3YeemE5j0Hh/5zu3j25F6rI43zF6sKa+hbRTgRiYMygWe+MV38\nH3bLqopR6CaTRQGxaWZsAKOB+ux1icPwqFHrUqXQEBi3qqvXSDoJzdDQTbvU\nzjoVHxslG6guyPJkTA7AeSxVAI2WJu9NWWYVOdhQjZVCzTZgLhStUMN4iLDs\njUdo3ww9Vxte5IRFPcq0K03EB7Foa0sgzscbryCm8Vggbbo2aPQS2lz3vhBs\n8XQ+gENJFzZsVSo+oC/42fQxfn7xhzDj+dD0lMCIm5cD+uDTMeBsj1b8m+l2\njk4YyTuhCFTmpitCfdKY5aNIvn8vyFk5dcPC04HFSL3sSa6pOWC5jS+lZLs7\nTCDZxt7nsvGn3L0Iho8+5fmQKnYJokMGDyNCCfQJvHQBWpu2bdOxpuFhPXDL\nxlqCe2m4oHSWknv+X6ZCV9nHhX3y82WC8chNR8RqO1oezae+Lpijdnf0DtL2\nZ9DcxV0MR4c9JeDgp7pifFTAe+WW70bUJxjhXKvjBvAsX8XcYC+pFERf0LY4\nFFLY\r\n=6G9A\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9791e3c6ccd0fc7ac51f53f5b5da38ffad6546a0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-37f0dc6-1622772118990_1622772185259_0.607517721973063","host":"s3://npm-registry-packages"}},"1.0.1-canary-37f0dc6-1622772136217":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-37f0dc6-1622772136217","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-37f0dc6-1622772136217","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"66e9688fe3766eba1988883f17096abef233f989","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-37f0dc6-1622772136217.tgz","fileCount":8,"integrity":"sha512-bQkflCHzYaC0xcKBQXQYeVKLIBt65ZWQP9SWXr4qK9xv0NP5YfUxlkZJ2uhTZr+DxPOuXlaQARejzmVsJxPT5Q==","signatures":[{"sig":"MEUCIHscYEIOmFVeJqlWzIe/PL8XIZ11j3xeqVVCvaHw0+hQAiEA+TlO0WHtZWHG2RKrJiG0gaqpyxVNGvFQIdB1z/tF0mA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguYnhCRA9TVsSAnZWagAAszcP/2jrjjIlXH7V4SLgmI7A\nTJPvHFeLh9Ucv5yMpZEY6VJgTEBKSTvc8h8aRPsQ6fJUg5ZwUEWV0583OU7I\nNyYk6RbALK2AkFQ9An0VkrI/jJNPsFYs4xGDQ7PfDsL5oe4NKT4NhxnTIoER\npObAPOon2Hne0JwO5JFOQoY+fXozhpRm4wzAajiBzkhjfEbqmLiaE5yIn943\ntqWEiNzAuts32t8lcCL4bgfV416s58uGDItvzi5/ZjejWSRDdpUYVKFdNnvS\n28HarHzXWKkQiVTs54JEFweYXM23nOGruvWE9keeBPHIr+QNgKxwaxUsQHCP\nrl8Nm5DWGnjAQjsFWtBsI26RdQvHdzOWX6X3oVJ6Z+tQ/+P0TASea3npxikl\nD8mf7iJvgUxZmRexdO4C/pMGM8tqSpsRxjZd1XjEnGZLWz7SqlvCpkmdOiU3\nQ2m9/SY3uUO4yOlKJuwTn4QVppuS8uZ2l8OiCc8DHfud63AgG0iFDGSWQN4+\ncfpX2qguL3HtSEbIhbT1srH/ZrAjAypNOr2wnC8eKAte9jaMBum7WJnLsJU2\n/PdohnIKQ0oq4B9sGvWzqJqrRd1TyjcduUZt5ZN9WSeKIqOOFkj+DyG8qXh7\nf7uFYLKE1PyEWZN50nhnabMWM12cjpAjs2e0x4ANx3o/j3yMJ9mbvT/stQul\n/yvd\r\n=AJPX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"19e2a674e0408d364bb06a094249ea9472920f79","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-37f0dc6-1622772136217_1622772193482_0.799346350915545","host":"s3://npm-registry-packages"}},"1.0.1-canary-37f0dc6-1622772157545":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-37f0dc6-1622772157545","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-37f0dc6-1622772157545","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"832b5e9f00528e20a0c069014c4b20ab1e23d451","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-37f0dc6-1622772157545.tgz","fileCount":8,"integrity":"sha512-qF5/mq11Wj01psd5sjTyJqIYwXtEnkFA7Fif2jyKG6MAp5sP5P3O6qRVmwLdlRJKBODhCfe+6olhkfgzTai52g==","signatures":[{"sig":"MEUCIQCGEyRml3IYgV3NMq3StSFS+WliXzu8i1bmD0hVGyEnrQIgUVQEMniegcl5nwX/90n9CicfhyGZKoVsdOg5Ft1fmvM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJguYoBCRA9TVsSAnZWagAAl3cP/RHAPhLX8JldK4nwgp7f\nn+PGyvx7ME2YLnKrgrWfI53c1JftI2nE6O1yw7bmamduEYAgjLgoE1Dn4IEt\n+3NIclLbkS2wYY8WRZaAElszAolErvEGwtYJFHov+D9cGUs9xfUYE4tb9u3w\n9C1hfYtosLWkv6RwS/cGm0/wq43pV6H2yGQQxASOdHLAYmfhdShwiOYqNk90\n2/PxTZTuOIWaxxggs7rvoAoo1z9C9h+MNU5YoqUDezgrAHIeSDOKTtnqRtH2\nxJPIWX86cTxqDHRf4TOGKs8lYH2R4mb/nehnjhnkuz/kypdUvxAHIlC+ANUQ\ndZycZmvCr5uX0eou7BhpJquRXNfrjUr+BKSzg19l2U33kZpUgClwPaj0k23D\nxk32tkdiyvHe7Xe8SVO3uLFHmjEGBVPr2BU0vNa3EX4vAF41djiVoPKjWBVU\nUO6XNr0WNWnTIh8WVm0EqyEi5ph8GJ590jcIjKvB5lSYG/7YSYUWx3otbnsV\nzLQCIMlHEdwL/KOTjV2eUIH4pGsPsNqMvalva8FTKE5tN8fgQann71BZ6X8L\noJpILekbihAPb12J/1IjRnTLX9jLL8iyPEsUz9t8Bv9waUVvI7HBGPMeLL3R\nS/A4LUwcMk0CWmgO2gjRF1oJcG54JBLmd8U2tbguGSkVWjsdULSQpA8GZeXt\nL47L\r\n=WJLH\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8f5334b628d692f12f33042c56e7d19ebb4af472","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.16.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-37f0dc6-1622772157545_1622772225524_0.0051463888907126165","host":"s3://npm-registry-packages"}},"1.0.1-canary-799abd2-1623031301194":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-799abd2-1623031301194","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-799abd2-1623031301194","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1428293919a20ca3021d22424e42927ed09ca4a7","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-799abd2-1623031301194.tgz","fileCount":8,"integrity":"sha512-LdcN/DGSK9jD7dvs6BVunYRzQb9irJwAG1KAVBhqD1C/+rpr/elBNpEhqorJWZnrrapW9RnHx8N7Fk8VNJcuvQ==","signatures":[{"sig":"MEUCIEW52fuU2/oSgpOo0xUXrgPF8Ra1AAmdMdhLSFINpfhdAiEAkj5b77VVNQIMUafsgSpQ2+Oa/IV1ienSZ39mQkoJ/2g=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgvX41CRA9TVsSAnZWagAA2KEP/2txoEtMJ+3AZKwsPFP/\n5hkjeJLUi0sAlcq7yaY99F+rNvEkLCcsQ+WZJn1ULKkRoUzU8wOXEdG7amz1\neMp5OfXeuNyotjHn8RWNb46KpHUT+UIU2UzXPzPnFwoxjOC/aMPognwkjP2n\nLo9DtGyhaIC9Q+ImtgVfRZLd/aFJn+WFGlq0+Ygi8RTWypauzz4A9aLxH1UX\n/2mluOp2ZCGCZTRteWalKuYe9y6ZImWqx0NfmNxEfzD8BvnJXb2nP09RXDd7\n196/0gUKoozzfx89OtPYoLEVSqLcOi1A5EcFpxgsoXnLHOC0F4tATlfI23yk\n2mBYRBF7utGVVK3wKpAlwz4aRKDyaKy7/1MBBKrsDegX2xeD2WIsvpOBosSy\nDHTvrIJ6MMioy4UQQ1hkUXMfz9uvUpxWDN01SL12fZPkICvA/lm3uDvGlvSZ\n6FEFzpPeRcaPm4Uflwbdbc9F8u1jCvK91FmLgDphRJtHVUKp60hA2n5CLoEM\nZsyT/V5zKWhnVY55JjVTt7nticOwpcKF0fs2PvRxfWAW+Y+dVeWUuyH6eZA0\nEz6oj2ETbi/m4IMjlpppK5Wvvkk0zGFNaV166sZ8YmAPax7/TQd9f85JxCqM\nWKYjFRN6s2AVf5/nT0BeL6x7t6Go7DIfC6DnwJKe3RZMLi+/dnV5QHTOsVjf\nJ/pw\r\n=UmOK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bd663c93d871b1c1f515e78894fbd74717b8ecf6","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-799abd2-1623031301194_1623031349744_0.7654259369102558","host":"s3://npm-registry-packages"}},"1.0.1-canary-799abd2-1623031322256":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-799abd2-1623031322256","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-799abd2-1623031322256","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c0d214d8df86b0c0d14098c6063787de9b4accbe","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-799abd2-1623031322256.tgz","fileCount":8,"integrity":"sha512-p6HNSOXjYFV2ggELTj6iVKPkJs7ep+9c0I9Yi/dER3yh8glhM364/+lMHwAKm2bAZ8DKTq/fr7M0biNYWbxKcA==","signatures":[{"sig":"MEUCIG+994zV7zgVScRVvXwQlpNtELZuvIN8TmjJ5ALRx6dVAiEAlVw/NvSvw8B2R5SlvMxIhi1BeoTHdd9AcfptvQ6KqnU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgvX5UCRA9TVsSAnZWagAAuuIQAIUg80S0noHsdcEqq5qQ\naoGTmfDyML6i9wPVTKl+5EjAfx32hdvR4it1Mn1r3SIdRlU4YYhcL9NnTH2D\nC5j7V+d9aPNHtkRfWTPLyAuTimHs7meMPmjKrreQNOM01nWjmcAnh6oG8GzW\nKBkqyOUeJPx5V3je6z+Whcq5e+R2F0X12QA4rW6d3vKRr7VSqpmxarL5Sa+B\n77HDkSJFcVGG3Oct0oWxG7ttjFCAY7LA3xXmODMgbhLJZ95/hnaI9mI0vDbN\n+JjB9hqYHbHKLMX9zBcnxoUqgsVZcZ51nK8IdboI5NMeqt0VE6V5rjxrGoIu\nR52QTrHh6fJFuXlILrgfZ1ZItCdq5lvGRY+PTspJuohCeaJ0c8F9zaRSWLVf\nfMcm6+CEppJ+w0fhsVG5lIwS19dkMbswPAOoJDiIhhba/NRA0P7ihruFNwOA\n4ONUJpVnyLZbgPjZF1CgxLCZ2UdHstQpnJTMNUVPRMco9Lx4HVWpo4ZzMt4r\niAJuUElKP9jvKI/iYDK92L0V1oT3pgKX213xFI7AsZ3g0jl2Pe4/uWrYt2rP\nFxLa73CKdH0M/4tPbnUclb0TWaj37RPAWLHD3kK3866Dsk1S8y3XH2mI+Uyi\neI2QZZDESHBxP6KjZOSQfdDqStvpyZeyokRYtQSHcVr608iLwsfubh58f1eh\nOzog\r\n=l+wS\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9c435839f51bd9f9d037be668fd79fb6b1b35acc","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-799abd2-1623031322256_1623031380787_0.38926590511729375","host":"s3://npm-registry-packages"}},"1.0.1-canary-799abd2-1623031341155":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-799abd2-1623031341155","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-799abd2-1623031341155","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"488f8f5d0792a496f7b14d6d8d376a37216408b1","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-799abd2-1623031341155.tgz","fileCount":8,"integrity":"sha512-ASKpW8DyR3lGfCiYMiRrMDZqxRbweHtrxzthuIHwERzG2gaBwuA8h5l+Y5l6Fg2rNa796wQNjhIjPn5b4Yy77Q==","signatures":[{"sig":"MEQCIDOKjsevYFP90JNGuyv0O9tMCJeFIA+t4BbJB6oSm/IqAiAsEn7l3UhPEWqTUUS1kdofbSIp/AvLcKVgmnzlCbew4w==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgvX5rCRA9TVsSAnZWagAARs4QAILOQcPUMHeR6XmS6PU4\nGRMhTeyT0e5OR6S+XKQSUMy4ePJb4F2jFi49oCDAxupoeC3OhUwZ/hoiVZzu\nJU98yzR8bs9HXHQXHqps8gTWfTHA+FfcfsAfk9X2Z3z9fbjupMJ3zk5tdkKG\nop9wiQrACWxxdsilFwJ0+OE5fhRlE6ayT/eGUQo1Jj03SDdlAobtQ0A+SFUk\nqacaAnDsoQV63bsTFBsbdBAgd84XPKFX2LHgf/lUW3eE7lGeytIQaQr85B7A\n0MDK1qk7j+TbrdUrlN4z1cEs+id/QuehxQjHiTUnfghlP5u89X4FvneyHl0d\nrR3Xqjkjx2OHxSxjGMpoHUgxk2oxyoOmyB93U5a8mOWt6bYwD4jkiIvtEW+Q\nc/Q2vnswSNI5+1pEm1O2/NHc5vliAwQsGanqYh7RXdRtPfLDWQ8WI38Wyeov\n4tgVZC36EDHpDeu7j8N1Q+FGzB6nfnFtEZ7vjn3XMoD/byHuqG7l1Fr3+aip\n3uQoFxIm9U3ArjFTfC2ZKg9kc9JxngdvXc1qDSDcJySC6deEvpmaeax8z1dJ\nFukh8JjpiBeLCVFqBdGdxAw36B1VplNuqI3r3pAShrPs6kLm6VaP3BQNtD7Y\nQsSiMflLElZkJamFxj3NlrHWzIozrUKGidBwgKINslxdi12VaZE1WFCVfFA4\n/6I4\r\n=QyuH\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"17de46ff628ea1bcb260c528ca758329bbc46ad5","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^27.0.4","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-799abd2-1623031341155_1623031403531_0.24336962858492273","host":"s3://npm-registry-packages"}},"1.0.1-canary-6890547-1623055506199":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-6890547-1623055506199","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-6890547-1623055506199","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b3109f427e380ac92f0fb3d3dc9b7132507ba4f9","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-6890547-1623055506199.tgz","fileCount":8,"integrity":"sha512-1bcm8UHUdbLE8JBWUZz7H8hgPiQUIqcAiKbmf/Lk8kbqDnbnaXybUbkrR8CsTlx1hJjq3JaRFmStLs/KiBHIsg==","signatures":[{"sig":"MEUCIQDbm6+a8YcgZwT6TGeC6czsJ9JByGailiDa3B5B9JoR5gIgCMx7RzosLWZXclZCzL8zanp0K20a4cuztSpSh3BMI5M=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgvdzECRA9TVsSAnZWagAAsDEP/0smUpXi9n7qgIrTNlwS\n8zj5Mkw6wIq3mPmYkFXCwq+XFmX/fRlYDFu2jh9/KZhLa71BXAARB8udzjoX\n8yH2y2op07SE7Q/Bru3BGPIAACS1BAE2N140MG8kJyM6vloc2fU3lAqFwV2p\nLE9ZypBVxp6uQO9uaWogxPxYnS/fSQyAZ4oC+NX5jLGcXJqdiIqdnF+hcZ/u\nt03wwUAMDZvV8O0qzp/mYUHmd5Jk3ekjaYQhVVJs3SthS9DtFw0PC/cP28Vl\naxtNPTXSzr35l2ECULCuR0gZypxz5Bq9mPUWqRolRv2BVfOPg22a0O3Zj9C4\ng5zg64wG+oqxb77pwrCh1hqglR8m8EbX6wRYeyt3xK+2q2GueLpsyV3PLqIi\nLCT21tniOSUX6BmX9X59S7lIaaJd/pTyibk80NWx0rR6wX3cDqBrzEpcBoe3\nQ6rpo4Wo4ypvh6suqok9u/pc1EbnncOAWtC+VA+EuzwhqTG64w+gmwwtQZKH\nHEcdCjZuvj+3EEFRKlKEPxXDypCL3+tMHb9VFAqv12tBrp6VHpX6dhHJwp1Q\nFmiQZkp+XCDzXdjsm7T/9LYClgB1K1zf/QUTqLtDCflLrA37DNSUD7rQPhDt\nFshzM6XD0zOmY/H8gDOgmWOpjasmKJigN5GHvWB+Ubb5n/BRt/mlg7JsKOyC\ntwHk\r\n=auiL\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0b9b912c21342dee3dbc4d844bd4278ba9e4982b","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^27.0.4","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-6890547-1623055506199_1623055556419_0.21424042211387273","host":"s3://npm-registry-packages"}},"1.0.1-canary-6890547-1623204100365":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-6890547-1623204100365","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-6890547-1623204100365","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7bd4f15407b81e224b6c0e7129e36d64566147c7","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-6890547-1623204100365.tgz","fileCount":8,"integrity":"sha512-RgpdTH8HwqCnjmWSZo69ymkT9Hi6+J7ETtTtGE5fMDs5MeyI4yYC5beXRsxn29elfF1/Te4IG0ToIy20XfExWQ==","signatures":[{"sig":"MEUCIQD+vMgdSfXLgSVP8OLlZXXhbDiJu6K1HjH8mHTEtM/DDQIgFlP6KU6hdrH6tN1AYyNIw3TvYsjNGrwvO+9CWWULuQA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgwCE+CRA9TVsSAnZWagAAW1sP/3SM3r2U09KE/oygaMds\n+uCACE4M6SdHU5QNdSd6OpmRSGN9BmUAIbY1bgWkc1oSY4WMkDt7EVaJXQNx\nmYv0XrUE80+8MyySIhtc8A14pP2eE+xB7DAskGQidhvLPKt/qkbxPg9BvOn4\nLYpLdZCcQOOpw3e8MMiIStfLGVphzGDCT7kQdbwaUvn5qqFhbBomCVhQ5aGG\nORG4E7dc1r+Gwz+JbM0vxfoJQiIs2x70L/draw2Cpg90cTvZFRAe7yecQzwI\nBQJ1//Csbqstb2uebFDM8aAlDHFWuLLSgp7vBPIjAhmvnz4IRYEsuw4m1Fvg\nZM5ms5LifFaGGK0WCuoaU80PPb62lVJrf+HlL04KjEPuLQ4dJG71gg9Ui/Nr\nD3t5N4g5ngDiwkkGsIxN+W81DSIvbM5R5kr+zF9nOptgwFlVABQsGK72U8DY\ned7AT/sYWQH0KBMWEC8NWgY2jlzfFsxapkbmLsscsOJPT1DrSMbYXvTyEKfG\nhwVbO6TLhTJdIGQGzpynWv5cWoL6ZOMgwnM+dubOqvvgfE0aLa3lf7zqPHkd\nINuLhnRSfCrm/YJGJEUwmnJSCl0HL1/GQqiAngMfMHucLU49eVqr33aLIrP5\n3u2xtJ9kawx1gdJBf2Yhy8uteTAFCKjHgitRcz+4hxURNUJ/omLG5gLTv8qI\nbJQJ\r\n=ERVA\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8c32db44f7ac1babd86942305b090b69e2ac11a0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-6890547-1623204100365_1623204158098_0.3945949009491869","host":"s3://npm-registry-packages"}},"1.0.1-canary-bb18c0b-1623636094178":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-bb18c0b-1623636094178","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-bb18c0b-1623636094178","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"de71cea8904c1aba6d5ed27aea225667dab68864","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-bb18c0b-1623636094178.tgz","fileCount":8,"integrity":"sha512-B7uziM4TNGctJ9Txf3aQcy2vXwWWilVYEAdd1HprjlufsGnfjcp2sqpnLICGcDcJNenufkrIcTvEJjrM2DNa2A==","signatures":[{"sig":"MEQCIB02sYU9YaYc0WNfeXn3hi4+DmrPKG92wq0/Q/9sPJluAiB4auPJ+R81IE2S4TDTJnOWpoJRP5pYOV5xmhBBDjTX7g==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgxri2CRA9TVsSAnZWagAAJkgP/2q4AlXS+Bgr5tF19YU1\nRc0HgvmasaZ7fK9sgStwkbXiKSH61e7V9eTICHAfc2Fh6oX03iF1kX/+W3DD\nkAW1wzwCrgdGZxG+go91I4gf70MFAIpHSfEDm785z+oxqrrkShG2QfObDQbN\nZpAnL5a4a4CCeuTnKpLnZ/yP2LxAaDdsWYJLacYrQmo+iDaTa9fDqgU7I2vO\nzK87F3S5qsxlfIs6GHO6fH0DmW+FttSl5jleg+OKzf6q0zDabx5IUrlRK1aY\nMD9gKJJ1oDOFDJHOs4ReDwZuOixxl8IEKmCMB5mm/frsWN4/B1PdSbV9eAvF\nzyxV9zIrdlhKkgkQQInFVfkZk2QNEfOTrEF9ZBuSuasO5Kll23zjhdAuqpw9\nICVaM3pq7dmV5hw5fmdzkhhNM93Q6aZdeEwMmkYHURnFmvwSbnq/95dSFJ8O\nfgT/jQPpdiAmRkEx7xUUOxmM9G3tGE5MbY17ATGSscnSgm0PIpmDMrEN5KWs\n2XYoIAlkV8jCRpXJmqGONCYIjuJzoUhxcK/lRmDQRoZDtSRWAsSKeWAf9xW/\nhiJGHzY6WdvFi2wym0zbHLApg7AP9UFv7bo+m+92wsTWhCnUKyTYPvq+yv/a\nHIA+hBB0SvT8rv24zEVOUU663CgP9RzS6IkbEBh27MltBHfe2SQtheG0NQg+\neHGG\r\n=8A4L\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9bd2c8c55151bba08ca998167b1d8d01683853ae","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-bb18c0b-1623636094178_1623636150826_0.054350349641284934","host":"s3://npm-registry-packages"}},"1.0.1-canary-bb18c0b-1623636116080":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-bb18c0b-1623636116080","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-bb18c0b-1623636116080","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"0b95a7ba081022171b1d23921f867a22ea7a1e1b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-bb18c0b-1623636116080.tgz","fileCount":8,"integrity":"sha512-li2MD3xXuVqrnBYhBFfGVjF1mH72810zVokWe2jXL3RCOsVcII3RfkoJhsd8x85XHabLB414mL/EbsSYntYOOA==","signatures":[{"sig":"MEUCIGqwbKnsXB+17pXmpJDwX1QTq6wn8LGZIlEljT4GYXX6AiEA6nT1XL5gQhV5TvLTJDLDCHWeASS9pzR5LYVAcCTqW14=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgxrjNCRA9TVsSAnZWagAAUZcP/11dlQsKgJm1k5mqLB1Z\nWCWcpszZSCPaW89eqtyaRJaNZRWEo9xDP+mAvhQt89ROyvS/ZnYM/hXonsPd\nDznr6yxYCmhB78Ivt6NoZqL1LjGPUoqboF08/65w9NTr4mPZIPVB2ttcLjZ0\nK4p2ELp6my/JFpyfrB1GVdNgMHhyZA/HtwTAdNJTlYqCZJSDo3+GC8qnGn3d\nEYFqoVFDuNhHyjcTiKc7svDJfrGFgSGQpBXlv/gwlW6T9RRw6R7rRJbJ4ouS\nrRldkqiI1IWZPPGGwrdatrEdgn13FfjdSl3KfxOpr657tQGm4vk6xPUvizMN\nnJTMYRTgnsbEb8F9EoCbJLrFsyvPG7cs8PJ5Kc2z/6FDfWPIb2BpQBKYYf9W\nT2xUtu0VhhQlg3WoSNTW0HovEnoLXIgX4IjqAlHZojt5oA/n7NvjpGjvXito\nvj5RpsabaGsCqx3qztv3r7i6CT3Rs/+/gaFuIHWB9nKovIRRESPRIyEtuDcz\nRWRGKlCzTtOP1gBJgP0WZW8BrfoKJh1GKLmDDiqi216K2FUlndd4zzYF+ODK\ncGUnPluMsm5RuvU1b8aoWXEin7hOofAPeGB40FHIMMZYHp1ui/H37slS8QCZ\ns9OwdmVyjwICu+WcqJSkRtW24fBxwDortX0vPwwVvKTniUanWxCTUg4a1Xkc\njTDj\r\n=n6HD\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"1d6d5e1c04b2bbd3918fd0f57cc2e24972abedb3","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-bb18c0b-1623636116080_1623636173696_0.02104331938257431","host":"s3://npm-registry-packages"}},"1.0.1-canary-a96e62a-1623895320134":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-a96e62a-1623895320134","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-a96e62a-1623895320134","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"9d0596d5aab02b60ba43c1cb290f9d6c7332d7aa","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-a96e62a-1623895320134.tgz","fileCount":8,"integrity":"sha512-TJhbgYXsRjPAzzP5SfcYxfrf+FnreDfcSiqkmkBgETHP4jFErl+ofib9/QIVcJ9EJJmd7M4Ov74tsXop4eJ5TA==","signatures":[{"sig":"MEUCIF/5eWXJ9IkGbheUxC72HnHZZud4Urhq0w4Q9lIHKAYkAiEAmFXSeNo+pWv1hb6QLoP6jFFTQnln9Z40c+xV0PLaPjs=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgyq1OCRA9TVsSAnZWagAA8+0P/jyYwJpEktKqNRp0vI6F\nQVos50AqPEp9DP6FDCXdKduoXu+STDGHU+1HCI2099d2fUQOY+0g4OoxTm5p\n4NSm8Ba17xIiGHIEKl5ZlDyTViaiZSEsVWKU/dCEZ9DzCO1jispbeYMUEPXQ\nF66ywpH+ahYeHVKgi/eDE1uW1ZnV7djQqE4OAE8iVUc1qaxjXDmkywUVVl7q\nAZArYvIO0/7R+2u2Ca0b0aPmE15VJh0imtFQgMMsBWKSXrAMAPPNBJzMpIpg\npXhBF1tN8yUjREyo1fxgrLlxlXzvcBFugB0qtyFFX6sOqqLZ5NUTwdV9rwtX\n3hYMnyn25NqQWUxhCj8LLhSeZsT5+Fi4/doW7S2Bf5s5zaXtfhGsajK7tLzG\nIX4ZWFM+IzwPZ3MZvgm5254ooHB2/B2WQk9xzlLFtPlMPBrRblxQBAqDQstZ\nxo01MBBsaapHd2oqtXulFx71ejQ9QgBchS2SNEQuC6d51pnRvUKGdvVmP6M0\njKKXHt1jhKnXBxytPJzaIHtbvISoKKSvINZSWQKlO9e6JN3yZkbvcUcApf4m\nseVUddqzPFYHpe4IqA/xdK8H39FonSYd8bPbdLCQn4UN67bw0GLBzBUFuh5r\ngzgfCgfZr/1TslFejVyz/5PPNZdGYiliQNsn7uXKJxg56bzIjYQeKg9JQOvx\nkBDM\r\n=EFNC\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ffa7bedd74b66d6df2468b5d31a29c2a067be190","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-a96e62a-1623895320134_1623895373902_0.6524478753221143","host":"s3://npm-registry-packages"}},"1.0.1-canary-a96e62a-1623895331260":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-a96e62a-1623895331260","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-a96e62a-1623895331260","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a1fd3d3d57b5fdcfd84af8dc2de523c9538e1710","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-a96e62a-1623895331260.tgz","fileCount":8,"integrity":"sha512-qmPzN69/QCGYcnmyBqjzelSiSs5x2m7sQWtaUv7nbRlfg+Tof1t8kkeJCpdro8R6DMvw5vC/Hw15HwDkrbDyZw==","signatures":[{"sig":"MEUCIQCqXKfJZrbCXhoaAKb34oIZT6mzpmipJ0hOrwkBfvCBRgIgVSrU50t4QzW1PasxeVG4nCvTcoiyrBfz0NKLsz+qxgI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgyq1XCRA9TVsSAnZWagAAc3oP/1EDHNQFMy3nF88yIKz3\nRBAwsE8JC/TXno61lmKvKOEkzTxHo8TvUj4y7BWeONHISlSUxqMBtFMfa5u8\nUyWxMk0NoL24AdMYWvdENwRlBFqJrdXYJqagRl0ix5pvBqRTME2odJNtkSt9\n10DS6W4Sjg8nJS3aWcAWAiACiEBRI70N+eBUPpMBYBSJARJHz+h1ThZtRojT\nEZnwc8Exp3IPLwlu90w4r8cPcUHojK6vXui/z5JRIqeXcNGjbZi9dmVNTZmR\nWfMU0VjlyqEwLspRbVle0va4y0fFjwrbvEWnpT/sKsGakUxufPiNd09qmBXq\nwPwbMDTih42eSu/5en41co3ItsHZ3NJ+pawuoqTZkmzmASSYfGyeOiLsnSFd\nwyuImIsYYzkH9ngUFGu2HMCqb780o2l+V9Iuk0Brzu0K8LKaCDVGIYFnDFJ8\nyzVal0AXWIHuQyNjUcqrzOabqJ+DruBVs+iHBh2SLfV62fdhngEWvvZ4WG0S\njUu8PtbykM70WFXmo2FKZTjED7PtYEhmHz5gkVEl/fK+ayTn3Jf8lizEDQVD\nPFdkibv6aLHxwM3wxFbUZ0EEDBErAECIQ/gthln+iV2OZ29BifXM4zZxrxIQ\nz2ZvAQxjMJeifR/E2WGagWTqKduSgXJuwkxJbfPZOzgUHC0ehrjti6boh9XB\nux1K\r\n=Co1u\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"f06f5f206fc1ea68d6f576e9fbec13bcc8027419","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-a96e62a-1623895331260_1623895383447_0.1424092143644473","host":"s3://npm-registry-packages"}},"1.0.1-canary-a96e62a-1623895353105":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-a96e62a-1623895353105","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-a96e62a-1623895353105","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"270e30bb4408200709440a0c2870745a1ca16e90","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-a96e62a-1623895353105.tgz","fileCount":8,"integrity":"sha512-UnqxTG/Q0I2cZA4vMKUDOIX9CxduL8Y5onCyV2FeVHcdh8iN9z24IZy2AYIEsf2cy8qCxNy0OvYkchCZc+mpjw==","signatures":[{"sig":"MEUCIHXu001oLWe3PtGMuHqx6VLdLaf6caIyM3lkDhHMx5rDAiEAzGKDch/ez6BDlzscJMx+WZzLF4U7bdyI14aqfk9JvKY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgyq1yCRA9TVsSAnZWagAAxK0P/3K33OdZe6tmvkNfk+uF\n4MhgIWKuRdqHstM0KAFZ1eZ2EmLbdXE242ZU12VSE296AkDsnvadEKFyrEj0\nFe6Oym4TBqQLoia0Cmg20ZjuDtH+HsDq7xzsUC72/ZunFhE/nwSA84Qyrqne\nGVn88uaY5SKCXoNq33W4oB6eDxJ473TiSF0AZlwxNgTGFb+9E9XAMbPH983E\nEdk+oM5nwamMbnek7RISjW0fsluFuaqH0+i9l8RGBIUkxKXAdSmwYiPvJZ0o\nNNQPgkp+mXVz++4aFxdNDjuuI3pQ7JHWBxUkECsEk4OIsn344mDKuFLLEJ5/\nSbrCbGl2f7yRPPNRvYGQrkbNMXecsEDt7xhm8GvYEEQgH7WYlaBKp2p78RWc\n0hC6QIbWE1SZxO9lENNqm3bVwhxPxnWPMPAFV7o7WUdsr5A/K53A/Q7l1L23\ncPrq+YQ2v7tKEwIg8489APb7PNDoBQ2yExredHPCuF2wKw5wkHdLbFLzwJY5\n8XijnldyUS9hApM439J7oZLC3kX5i2uQqKbNkD3z6pxadoDEJawRJeMBTg3O\ng02yPnDZzjYcAo1iTIpSigm+AQBYZB9TlUT5wLaqfWONpOE+ft/2NQleTWLs\nb9VPI0Zbac34xbDlibka24Gm9ebXvdceIwTD6pO20Ybgr+551tYjGlRMKQ5N\nIE+y\r\n=5AVJ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2e407a9cc08723994a4339658cdef76111cf3824","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-a96e62a-1623895353105_1623895410094_0.24339184634442312","host":"s3://npm-registry-packages"}},"1.0.1-canary-4b6b557-1623981696441":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-4b6b557-1623981696441","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-4b6b557-1623981696441","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"40568482c01a1ae264c267ba60d260b7e3102257","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-4b6b557-1623981696441.tgz","fileCount":8,"integrity":"sha512-HzpIxXpC4kqWrUuo7hl+esP4AkZosmc+Eym7lM4lGFStGL8AR8+QzF/ZYpg1psfaTBJXGzqLRwdD9dtzZLGJPg==","signatures":[{"sig":"MEQCIFrYffOjpjnqU8xTX+Rwt8cUzasKtgOEvFknBUmY8X0AAiA1/V/BvDCI/U46Y/npe+i9jeHzKwwBzpGT1c81vIJf6Q==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgy/6zCRA9TVsSAnZWagAAm6UP/3AUAnFIkVfiqezVtCNs\naimajktoa4uSaYjUqpNvBT0JULpLsyohufR7GON8te6sepA+g32R7VlpEy7R\nbaNt50DHfj+plNgHcIt2GtntLTBcHsMC0SW4UlT1+UE3iR+GJby6jGkNyl3s\np/Jq263PrfqlGmLyEcWV8BxunDkW7/cTzyUEoohzBqav9U1GkvJPZFiEJUCq\nkuYmYj4AWC76xvlzH5hgsrxtF+lgDJBqaaZAN51iG/Cdg8JCNIq5U7IXpxE2\nZiTrS/Bxwl/9R7zHJNiT4rNoouF2iwKwJ1XDdSDWJTJ4Ak+oP16+JQ5ESXQT\na3OjcPIQqqWGBvrZrFKbJdcnABmPuGB5tnjUPKEg7wN8AU+nEqpJSVtC3W/L\nCk1xiURYEFl8KQpQPGOz4a9AY/Q10Vkg7KT5aaeyeNJuPSC9dncuf91ZAgxV\nqb/GE9IxM2VreJVSp4RgjLuIrk45kd4JMmAIH5Z8YZCBd1DM94FSnlT582rc\n8Vd3Y5UZglKigNMgxGQo537DhlTb3mWHkVX20BdAG1JNyC3cwmRsJmJUdfLS\nrPhLn19gU9taC1BObpYl1gTSSVJGFYB070h0cRfs+DhP9hxC3b0j8cNRnH7U\nueBXuYW0zUM+aFY3Tp9x5PdSFuNVasJuavneUkIgDj7ZVAIqVeIwGoBlxQTS\n3ies\r\n=OZmj\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0d6edd1ede4c4935a65398355537cdb9326b5d8e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-4b6b557-1623981696441_1623981746500_0.2294269755412257","host":"s3://npm-registry-packages"}},"1.0.1-canary-4b6b557-1623981706276":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-4b6b557-1623981706276","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-4b6b557-1623981706276","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"bfa47387f2947fc919703fabaed343a6b596820b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-4b6b557-1623981706276.tgz","fileCount":8,"integrity":"sha512-RF+luc6hOqZmjwHVotm5cumBJWPyFS9yg170DbZF8q50oWX07jMejLDW6x5ss07J7hzDAaz6KUcFVQ5PmejfPg==","signatures":[{"sig":"MEUCIQD4txv+RG3YMCGgiCfFSzK77GMN4CRHOwvtpP1W3NgD5gIgZRjeLAWjSWv4XZWFFgwoJh4muSUjFDBHbOowntRF9NE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":60061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgy/7KCRA9TVsSAnZWagAAjmcP/03DFTuC5CreDHN3Pr+B\nzJD6CyAy2kyztHV5cSXXnRK6/80fuw0dvTd3fFfch8qvV2VV11pUgRqEAZ1P\nXCPokI7yQFBPtszD23K1Tss7DujM7froltQIPK366edCVCf3lKASwT6XfBCl\ng0E5eWAM7i/kyWEsDDoXTjcXx9svxxwJj4PZucMIOxMC5lIgihgM1DWyYWh2\nzcnAfVu86T9ZnSc22M+2IyK3uRDY4GOvuFNv/4UFuUAzmqeCQpjsn5JDjdFQ\ncDP4mQ+n688QyUSaQhgvHfdrXVcle9EqFtoIa7u7KmU7mtkXskBaiiAwaOli\ngY8GqY71PFh9u8TBxccDHM3HwcXq2ydQfwQ4WdQNautCO07izzif8Se7w7kz\nRfVGPcKzp+kD9A/mqlu9fsjpA60vBkR4CLwyywCw3qoLZSoaJwcr4VjP3l1E\nbbmdn3nLTjf2DLoMLExLhsD68NM+X10CT9P0SUHat+j8ZijjaOuqJNb8Dz19\nDwAhvP6XK7vnzhFZtnkvy5jmzq+p5yFu48WGzXmL1N8qaShJWDpygJt0+DRv\nP/nLOkLGI5HlX8rtfAiq5RtSied9lCld8uk5Icp+2s8beUlf2u+Do69p21ek\nOG1him4AEsCALINbJTPYOBadEq+hr4Wr+N6gpPi97LXWs9J/aQCFyG1zbNXy\ndal/\r\n=JpK/\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"791a9402bb7a7c01a8f489c6e8a3bc900b902f42","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-4b6b557-1623981706276_1623981769962_0.7341864298751517","host":"s3://npm-registry-packages"}},"1.0.1-canary-4660650-1624240879986":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-4660650-1624240879986","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-4660650-1624240879986","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b30a0957f3d68054c680af99b3b89a43261f7616","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-4660650-1624240879986.tgz","fileCount":8,"integrity":"sha512-kLYdLYzwg9TYjc/bSEs7xTN4vJGYE7QlqjCWDmLNWaEqvbQs/5FgfAbmKwJIKtoEBLjbXFgHHCGPyMkxOrokmw==","signatures":[{"sig":"MEYCIQDuYZ95joHcm4m2/EpyzueDC0b4CyWRkFcnV6higoRyfQIhAMrvrvr2StkA0gYgdcFfPTKmYh9alSEXs5HgG68EfQQd","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgz/MjCRA9TVsSAnZWagAAGTwP/ihgtcXCd/cQHMlIiUmD\nESucgpU4iV9sS8veV+wQY29yJOmjZG6p4h1AT/OW/8DHqwLDNq1B5eM0CDuX\nVOmfYyXTx19X7EeZEfQLMtUmOmBIcw9FalvgkOI9tpJRrwTzQUJRVoMwHtzH\nW01im7artdzYbfdHYRIuYy5yoZ+I5WbsmAVOhg9QanQWzCzjlitGKLRWQAxg\nSTgxa6XNuXekrICcojs8qWE8+YCvgL3xEWut7TI4iheNDklXPsNA12pTAF8C\nqVip5dRqlrik3arvi9qhk0uEoIrTSdTnITQjajFXeLXweO4jbPqi6HlYiOAL\npwDI/5cfQFXwr4dIOOpZ2D0OfWtEgaqRNvXhbz60om6pfff51Me8iNRi7/ys\n/aEXVAQaHgZHJMKdbcv1B9T3mxTeNYt9uGMDLp2MrQxDlhUXDg+6kFqjXJmU\n61YEbpB48U6dnuoyvWvFzLhEhcFHzRlF92dAvNRavUFNk2skEwzmtqpLlt/E\nLhWXd0rCcQqMyPcOb4/ssLmFiaHDA56z8UivTw8n/iL/yzf9wXijIA8/JZCE\nFNvYH2O6zYruS9FEeq//ckkKqK6278a9giKAtMJMgtdLK+6k6YRrsv+0sRQ+\n9NOZCwoeqRKax76sQHRH2JOZRxSrrYBvvPseL29a9Hn5vsd4Z3qMu4+EeMIE\nHQXz\r\n=mEh6\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"59095976764e0da367f6164f0ba1a164acb9d929","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-4660650-1624240879986_1624240930546_0.23495901929141194","host":"s3://npm-registry-packages"}},"1.0.1-canary-4660650-1624240894473":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-4660650-1624240894473","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-4660650-1624240894473","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"63b3cdb7aeec77b2de005f7ed1a067c4ff476969","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-4660650-1624240894473.tgz","fileCount":8,"integrity":"sha512-+cZOYqsgzxCu6CDkFd6eZmk/lF2FQj1awFrLexBuJgIaMj+OYoZtPOSYR4PXfSuwta1NlVlLX5LQOMbrLaGPuw==","signatures":[{"sig":"MEUCIQCMRXbIPtWIq5IgySrZ2SLie892tFSjBHk534eAbcK65QIgdbH5N4v6jUrgyPZQ8ccyo5kMFU9iV55+yBRwGr3omcw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgz/MwCRA9TVsSAnZWagAAYGoQAIbAwpaiTkii/1SUnOfB\nvgWN05Z2ps740kwb1GFvMij9gaNoicxH5140MmlN4FOBmCH9YG9NumYSdiJH\nMtnKSTg8au6AQQlQ7zsrF0OmV+HZkKCAZLaIw3jd3LJFChtTx5CsxTiAlCv/\njPY7FlUI587g/4hswN0oWflW79/bkeYL2LuGWmui5oBguePmYBISt78wEtWr\nFdb3YjuQyPoTiIKkdgf/+XZh/C9KKnIu6zli7vUz8F+ZjtHMpNBTgjn1crlr\nn6ZvPCSivOB/dB4izI3k0XKFr5oN+m2MejjsAmbRVaf3UOBd3jAe/K5Q/gMP\nmDmuP7fkFOD2dhL3mcTiDV2q8gPjh6cdDgjW/mw4xw0neTgj0Am3BVIAu2W/\n6JL8Igc84gcfTDUbTT+aSCB5PcPYibv/hevm6P2gYuQjbsJsDeNzGWM6xt7W\nxM3bVVGqCTq72Ws6XIYM2/XliXUEz9pDi+F+Ag6MAFFquaUBMX7RhRlNPuvf\nlNXezM9GgKmvDjS+LMhT5u1tGcQNQxYMYzUz69hN3td37Romhnt9VyDjwlqp\nDndGvQnrsPd72lZWwpkeWt8+d3+B6KEl0PHfz6Ai6VL53t2STqi3c0Q1l1jj\nRgVxVhhHLFPuQhbOIIS2TipUg7glAUpgXVbzVIgp/9yRLs1F8zXu3oWGuCwf\nNzTd\r\n=sBRN\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"de961f46bac5aa37203e64ac4ce4ae528a7cf4d7","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.20.36","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-4660650-1624240894473_1624240944444_0.6990340751768915","host":"s3://npm-registry-packages"}},"1.0.1-canary-c2c1dd0-1624327276179":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-c2c1dd0-1624327276179","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-c2c1dd0-1624327276179","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a40e5cf0cd35f4d0a08f52b70cb53b7be2331fbb","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-c2c1dd0-1624327276179.tgz","fileCount":8,"integrity":"sha512-SndHWYgyooe05jOq9IhE4p+ZNUpIpZrSd8d4Fc0rib7rQ2PXFZJ6JkJRQ5/tzx4l37bkAWPNDNio5X3d3022AQ==","signatures":[{"sig":"MEQCIDOVti1E8pYcCH3oUD3VwG5G+rODW7tuFRubHcSl9gNRAiBBbPqMmyauKFhNk3moIDRybD3u7ce3MsKyAOL88nroqg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg0USZCRA9TVsSAnZWagAAddIP/jbkplpeVy93KDccwYWY\nEW1U8u1KtLHHcCjGDSd8tVT/tIStsnhAalhdQ+oSZ/UaH6KGnG3t2yw7Xlpn\nk6QkwjQSJDhrR8N57SEWacn1yV/FB1/Ha4HJi5hLlfir+lY/AL4YiFDmxxiL\nQiX9hvcbiCe89/9f0VQ1bn77dhfi3HklQGLsQSsmBCrswu6AbB9gH13uvapP\ncn4xz4woK/0lmWMsD3G7wu0TshdKpajFPreoZn8rz+hWw/k7q8P/YKHqu+wz\nejy+rm0bsa9fo2zXVif62SmJTmZD4lrwKZsrR17Ty/vi9hZsxLvvyPwk0cOu\n2tKFqZBwO/kecVFG1cajimuQK6T5elWrKRpIG7QKaKNEyrf4tzlytXOC0ysh\nZ/YnxOIkGo15g9mZL4IDZZbtU9hjWY9WuLT1L+E4kx+tK0hWI+nFOggktfhD\nyzdpPik9dIIMk0EMV8AVCVoWUpQzcNDDzsZHgIFcnJeLOzW40ZSXnJx6O6ND\ntgCVok2AOpiDz8LKCIGa24qni2qzC95KyoEaTJ4K9QKRsrKSYKQwFkRE/o2q\nkTl0JN23Li5wivhbLwQto4PnaOsI8j047wDjllM1vuCfXDjSPGc/Rwk/8Rf1\nEQRo8tHg1zNSdB3wSHlnK6W2yuX+3qK6y8IVBpsfjaQDTF9lWESw3aHrCV42\ns7fy\r\n=0XEe\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"942094f1f2edf63146e1d74f4eaeb8798d6cbbce","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-c2c1dd0-1624327276179_1624327321263_0.0036382695743526483","host":"s3://npm-registry-packages"}},"1.0.1-canary-6148f5e-1624413704884":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-6148f5e-1624413704884","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-6148f5e-1624413704884","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"76f6e9541656c8dd948d50b71816cbb48dfa8ed1","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-6148f5e-1624413704884.tgz","fileCount":8,"integrity":"sha512-uYbNiPEricD/fMYsuchEE5faDfHgNVQtFuFKvq3AmMCT8irRI8Zl/GMMHMR7YmdJJRJHpaiA1LXbre/KBnJEhw==","signatures":[{"sig":"MEUCIHzUSybmX2m2pPsf7xcpUTNGLX6c5doy8UOHJRuQAfUgAiEAkltxVWbsHqjF9zJQIKytdrTPwfpwYpGofLRqVpS9P1c=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg0pY4CRA9TVsSAnZWagAAS7YP/1dH/HXTEgxVjlH3v45H\nm9hV8SoFTwv/Ka2uNnmXGd56Z8Kp4ZVUfGEyoMzs673fKlyMeMOeXryB007m\n98sHj0qz3dZWD09woLUWgAX7wfIH5Y9wX+uTWNrO7pTbNc0aFgD9SqSG3Ix6\n6Rb1q/PEmOm4/y5Oc2CsNICGHG1ReniZx/a4V3RJo80F0OdmG2ASyxsRNjBl\nCJLjsoFBCtfq86MxsYqm+T+TnWQ5yN6RMR+TXmJVuztBIe124TiRBryDX4qb\nKgK+KiENB2KwrBjsPuD5f6/igAdGwfg/bse/MfSChQphZPdhsDOoa7uckgOX\ncGWVWOCILnZ4nLsgfv471bmit/PX5u2rtTpcaCC5ZvGr8cMuTUE5UrbS7gW2\nOC3rB5OadYmxaladGQXofZszJM+AEjEZnTFwObyy09bRNkSftrd5jr+ctrpl\nbew3IOiLz9hZnERJNXheH1kGh6fE6Hekk18y2cxzUJalmNcHajj5poIVoOyI\nzhI7ldx+97f/pM4MvTNH9bVJPFKiFXd0xIS0oydQbkCry4ESYC14Q5zPfBPX\nOy0lfxOG1osh8jeQyAKlDP0Tf3WRUe+DvkGdgxXBfylLe/e+6iz7va7kesdS\nzNnxYhRscWuNH97X3OmbTeyK0sWd4KhTdSpc6SCbu9B830IjOGXCpn+bhZsj\nydnP\r\n=WT0f\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"83582f374979c732ff76036d2ed62a8b0253cb19","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^27.0.5","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-6148f5e-1624413704884_1624413752246_0.19303878720064893","host":"s3://npm-registry-packages"}},"1.0.1-canary-6148f5e-1624845686121":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-6148f5e-1624845686121","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-6148f5e-1624845686121","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"cfa0a475ae044c1ae5817905829f9905079237ae","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-6148f5e-1624845686121.tgz","fileCount":8,"integrity":"sha512-1LdBUgV5ukhREnw3gWLdxscwc4QoC+OJkzNdh58W/je5AIAB3XOgWN2EQkabuhyVoAnlABEt3EAgbA2IkzRM6g==","signatures":[{"sig":"MEYCIQCocoq+dCB4nkQBfRArklJcNSh1fGfT3pwoKKwa467z8gIhAP0roCYkGwnq/jTJx8qqtdY8Bwn/vP0jZ8VoRUDF07Oh","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg2S2sCRA9TVsSAnZWagAA4LoQAKQneiwAw+a3EoVdRZ6k\nMwmTPpykQkoZITc2ktyt3T4uy24xnOuJW8/pVle9ZoyhsfPxSVwc2NVRVfHc\nGfXpt1QsANoT6XZsjtbZbnEZi2o35k9W1DGvZmzzmC9Rcq5oNoy7G+JXXViE\n3WXozljIPv0oZYoOS3KYn2ro75AxnNz/TWai4avhqh1OxvfCcRTIFX2x4Qgm\npGWvRs2dZMbHLjDV/MisqO1cRDF8lMK2RjDc2LTsajwRTNyjFBAvWbz9swDO\ntlO1TRjw+nIQoGAskCwAt30n+Ut4aXg80+uAHUu9Lwj1exsWBqFwE3DxvW1z\nkqJMxjPr1tGaIvFqiYfQnocFifTg6EQF6L9N2yMhBawFv42agP5885I1NUku\n6/jEyIyP2cLunpuqRzXOUStA6UA+aoqp9TSELTiNw/WWuAvW8QlL7iM/GMmq\n44JrRs4BpjAL5s6QcJ7MAm2FRaqGDKfmAz7FYthXzicZ5JulmiP93kwb3k1W\n4FLAWEgM47exRe1fkORn6R2+vLiQeCZNENuH1LTRCVSrun8AiSz6K4yXPY8T\n3Y7XDuM49KmsCJiXantTtC1fh1CPjMzPPVO5KZxmDMUL/EOStf5aDwtYEqvQ\nJJt/cWA0j5bSCBGwHSVuThcvAzsOFaPCQjNqX44zrjE85mnr5MwoMEUUK9gS\n7M1K\r\n=1ql2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b2f85be345a32d134c4ba7252f6f6a20aa606f86","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-6148f5e-1624845686121_1624845739479_0.33557625885547915","host":"s3://npm-registry-packages"}},"1.0.1-canary-6148f5e-1624845697597":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-6148f5e-1624845697597","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-6148f5e-1624845697597","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"966965b5e210de5fb74b9c54254793c712205c1c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-6148f5e-1624845697597.tgz","fileCount":8,"integrity":"sha512-Adu0F4tYI4cN35eAd1gduF2uUCVeNj4CEgaF3/XpspVs6ZeoVzVoE2RpidMV/VcaaHdDLm2cPX9r7cC0wTuqeg==","signatures":[{"sig":"MEQCIHIUzccBStssR5JUoJcms5GrYdofqCEwNLP9I3PgzONgAiAoTGsLQALUya/x9xsRNrrwUktsLt9Ppy7+RQRJYTD/NQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg2S20CRA9TVsSAnZWagAA+kQP/00xp0O7WsrJZkvThocN\nEMe3tXFZ5KEdknj/TDyjgrt/Z3VTvzOqUCIxiyyLlFaq8cKQrPlBjDX8x1UA\njx3Fti9MrC7MAcqi3beNouIwYCI8t6s7ZTGXNYFRZuZnYA2/2YPT5F9KRoX8\nqJSBBNavFd2VD8mFgidnFYTWelWe3DMH29QMSvnofGeCgLZVbcZp6NvG1BTv\ngDsenvxO9ohxFzjL99Gi/szjMftJvgdo2zy7nlHgChA2Pobpy6OP+hAOiL1g\nfk5F1326jrWAZWz+QD6ToardyRRW4la2KcH2OF4SpRHqVgQKrthusqfxcLRu\nJjvpj+QKSxe2VCzZtjJ3+NvIsqWO0gPB+z3mlPm3fWIGMk4F+KgtY5kPeCFx\nZIJACgmPR5foMjzuCkPAlSoKSyIbrULDrxGkJupD1oECfKr6mG+/0oivMP9f\nq0ExnNAwvLSyNnkR7bxtVk+JpaDpEKGaBk0TsTzoJ997/lgD/zpQb1fmy2ul\nZhMoCafBpqhHyQYd2SSEKKFYUBEMe91zF3nUZFad5rca7Eb/03cl2ajPIqGZ\nxgNkhroefmKTO8lkMohtcNvXlSJlsyqS7dtTBXhuOBIM5IFvgx1EHi6j73tg\nSEhJUex2t2HB1RihKOKNL7UlSF/cM3tB+6PRtNUee25E6Of8Tb1Tt7n6kBsR\nHjB5\r\n=Ceny\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"5135572ed9344e2a048daadc8db0c45b0bee5db8","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-6148f5e-1624845697597_1624845748291_0.41359687523547084","host":"s3://npm-registry-packages"}},"1.0.1-canary-3c24b8c-1624932095173":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-3c24b8c-1624932095173","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-3c24b8c-1624932095173","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1032ef9c38d146891ec62f0c67dbe529dc432302","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-3c24b8c-1624932095173.tgz","fileCount":8,"integrity":"sha512-aE9sbnwLj2YS0R84aUVsC0uyzzE/Pk8ADfwVJRyGz0L/N0rsxoVhgxe/I4eEE3V30FaC2IdrTqFeq2ckGsv/0g==","signatures":[{"sig":"MEYCIQCNgSxpjaLo7itPM9WVRLSKsQYOarkPnmnTn0P6ZBPq2AIhAKdma8tW4ynB5A17T3EDtJDB+1yboqmPASWG3t6yivtg","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg2n8rCRA9TVsSAnZWagAAPdUQAI0YjdWNrZUTQp5IT2tm\nQ3mTm4vK+DHg4P6CmQsyC5RV7l82yuB0xsW7ms/fsBFeAba7UGdASMDupH7J\n4eaaQItu65pd6Dk5ZKvnDhF1blvZIx6eorGa1rE0MB7q6bTRKn48SaM15gXm\nrk/f6tw2Otpr4sP/9qCvCmvOAoH/BMfvpizVlra0J0A0Nlj3DuGKpN1lxhRl\nkCDaNfcTeeQZTtBprQPaOat5XbT348DEAjh/Mb/v/3JBvg/Bk32J8uONF/Pr\nYXV6YfjNCA9jt1Oryb3F3ktBPLlW3DFMsX9juDKKRC5p6228T/EeRXESYHCP\nVsiEPxtiz5GQxOa8SFrwTNvDlSFTmi2bDTycEVDQRfAb9R2Ypc3sqiwblQDa\nMEFAolgLmo2QzLBBUeM6eTdvElUMU2kMJ6Rk4Irb3ewWQ8A2xBadElvGNCwj\nE+RqUXpiF+BzkgFyIyaYWMk4Pj2hNSRYe59J/I3/NcPaRj+Lmc7CS+zcvGck\n3ZGidTMQWmIl/Hv0V/FRrIOyIA3ysgLLdFoj3X5cjxl+ZjgDRol3Q8ZxAKJq\nJF70Y/5Ks21o/khnKWyceO+3grkye1aAztpE1BovYunRism0ENAu/HWMn7bu\ndUl+jiMQOKMLDWEpz80lPKxijjXgk65UyP95w4DJDa4yDbhJXkAAS1Z0Gezm\nDu4i\r\n=IO13\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"d10aea82d55a3803b7b51eda125b3e8b93aaf78d","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^27.0.6","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-3c24b8c-1624932095173_1624932139309_0.48297751642126685","host":"s3://npm-registry-packages"}},"1.0.1-canary-3c24b8c-1625104915737":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-3c24b8c-1625104915737","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-3c24b8c-1625104915737","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a38a5ab9c79ca4daa2031d4f22485434926b6b94","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-3c24b8c-1625104915737.tgz","fileCount":8,"integrity":"sha512-+51FmQSHMmR8bTES76iTKBLP9NYZ+yQhLLpcRpNAbmvo4gRhnh/3IjFjbdRluQz4FEeuJGoO3X5YMOU1vW7VFg==","signatures":[{"sig":"MEQCIA6kcs2cnk3BqlSwr3T70vUs1/obVpfSmW1VZHomnBz8AiBH88MiXU3/nZ1dc8SB5rI1D8S2lXYpuzwGuMp3PDZw4w==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg3SJGCRA9TVsSAnZWagAA/vMQAIlW/z6b+P/wJKq8gQs5\ntQAV1c/dEQs1GpT9LG4N7JLT9K/Bndx4amdfIz94gjj0jITYcGvHDdYtnDP8\n4WtJn5CUJFeGhPLlHWUo4hoMC6cx3pFu5gJN8JVytRz67vFwP03E0md1p8/T\nQYDqd6pDHCZR9QUV+OouzqYlIrZ4Zo4wHVA2MKgF5DgZqKZigQyOhysURhqe\nlh+iAy5mg9CNlJhAKIj4fkcqadqowvXuu+cb/1j9VWG/XvWbMpIgDOfcjFdR\njI7NYLIghMclknWm1icotWzO+QyROxc6VmcHEYwR01ak231S7LlpejoPDWVi\nAucsDjKuxLrr6cYAz86HztuUm4bg/LrOOC5o25RpmxDy5vE1tiZ3xSeEqkL6\nFB4YpfNmHwTkZjxc6lqMFby+1pNeTChoYwEffuOZoDU9GCuBfJcuBA0c9rhu\nG0rEsDAMlA32X8KfHRaDz7IwuZNm412sQlpvMyqXPi6wcSpmNRK8odmu4lFt\nSMmgCKfFKH+y2k2PYFSzlttHELQwHZghoNWfeo+LwvB7TSISO0plsR0csjG7\nmsrYuuD4koPLyNDJ3M9ByRAFdCXdPmf0dxRos3TBHtlZQHhDTGJCoLGajBgD\no1kbuCeI5jjAp8rD7fc4/esBluGygvCodXfczOjwxfXPZ1oE9+IQlZn3BE6Q\nxCgA\r\n=YCH5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"828d49c67d953c08c93123f99ff77299d7df26bb","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-3c24b8c-1625104915737_1625104965584_0.9652696476837297","host":"s3://npm-registry-packages"}},"1.0.1-canary-3c24b8c-1625104931950":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-3c24b8c-1625104931950","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-3c24b8c-1625104931950","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1a86b58e40ad566d10ec95898becd5836fd23dae","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-3c24b8c-1625104931950.tgz","fileCount":8,"integrity":"sha512-v4yn6XvTOhyWwSYScm/clxP/RhavVajdbIpS0nwR/KplTR3xMBShQbp1JEUU+TKtpt60Ch9zWup9vDrYIPGVvg==","signatures":[{"sig":"MEUCIC3J4uB1/SR8xvyzKfQfApt4zrH2KsNBnCEE7PA2bYohAiEAgZp/I6IJ+5IRpKdiMsSItpbmSApYWoU9v3kMfJqrRcM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg3SJeCRA9TVsSAnZWagAA5ugP/jwa20AAtS4CWHsrRlxt\n5hFs6Qsm9SubG1tg9ue3nhRH+ABU3OVaE+Tk4vZEBn+pt6A+hZp+UrdjTUbq\nSp9MAU5mLd2piYdhvvKpf4XgVNJiEH5MdURI8W2yI5No50Fj1z4Vm/VD+bhq\ncjHzl+4NJBURTRIsCR3pfdQ4MyjmF9bWXRhReWlwU3lhQPcvu2J8hAiRkOE3\naEME3ahNWla/Uup8xl+s0q7YqcAqD3ZibxINsNr5Ei3G11eLUQo4o4mQXfQC\nkDdEfwLyu2dohL/MkKICfrUmKJiS0F0t1fxqiIzBY8NVHQ1hA5cXrvOFh+jy\nb/TyIw6vb/D/kn6N9nbVIwoS53y6XR/hN3NJsNRYKz7zq5uNKxoCBO5cnCM5\nEf/nt1RfaF8xm8BnMcet+QqbJe/iqUFhVoXHiOOONvNkqFyFq90aJtH9ImLh\n7ANezLgROhaENDbD/wu95jIJFh5E3OuLnOfCnNV3ORu0s9GRcCKgSQCuqgT7\nv0DiKVOnBvN1nwnBw26JyrfUkSw44eIsnWp3MR9Q0O72LwGuYo4XTWTiLN4K\nsgioRwg4ptIF8lK+u8+MA3j0jSY2E6gD5ebuCA9SWq+7hL0WcutTEwjGydXh\nLk/EOMuHOPJmjE/fBdOWJT8XsPctbbEctyekKFX0CA/Q8VtmAHVs2wnmLvnS\nwPuu\r\n=s3P1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"7d3162c7ffc46f81b68a6e6217fb63b728052cae","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-3c24b8c-1625104931950_1625104990331_0.9815695210082704","host":"s3://npm-registry-packages"}},"1.0.1-canary-8ac59cc-1625191292560":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-8ac59cc-1625191292560","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-8ac59cc-1625191292560","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"047976e53f11f08beb01a97014c7a62c88083eac","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-8ac59cc-1625191292560.tgz","fileCount":8,"integrity":"sha512-q31AoN9oIAFcVBcAtlb9WQ5dvFXNynj0Q6UDe5yadnlAlBy9vz5XuYfieG+Itsss1Kk6+NOxmskTu/9QGIfk6w==","signatures":[{"sig":"MEUCIQDse3QYmX65PVtMn7StFr2oaIcVh6YXRLwcvH478pggUQIgaMIOtXXnFAeqhkqgp/YD2y9doqJ0r5vl+ZKrOMsJhoA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg3nOsCRA9TVsSAnZWagAATjgP+QGvzrKMDBbUOsgt0GWl\n0ObcOaDaFmRz5EpQZUb5gOq/f5LjYsGGTtKvGX27qrNcvko3li3VbJhxsbou\n/MmGqGKMvhD38iQGc90BAsr0mfsQjfnZUUobhARQtk2pMJ1XQMjA0MZc0/HV\niA49+2+W4qIC/9UiUaEAoOFuOaSL4xWSmLnzSxV7doMiaFvIaM1KpjmYzwnY\nJ5TuHcHFynEPFGgFhVbDNbLOShsAGDk39eG3gGZ211eO5DFd/GyubktCrJ+9\nIioFk+Q0MBpVDXX+FweJCrSNTb/LkoHMvK9vM5ipNLYoa5iqWQsbWCvQ8Niy\nQjZRzwBAOwwyM0Lfiz4G/9MsfAJFqLFpzOWtHq28UwonKiuGdAv0T5n6cq4a\nB3cEZHD4QPTsnvc481fLlLWdPD1fGUhKBfL7LGJKLbuCPwh98a9LKZsFHJpG\ncoOZdHKWOCuPNL7YOdsSialeFmQ1yAiXatQaPkIanhfJDJikHEuZ99rDFUhl\n8ncb9RCEk4hvya/7xqqndg0LjROu7loZShlPibtD3vAu1Oo8mwxfIqK3JTlj\n6qoJ8h4XQEpZ2CuAvXxDWSV6AKxetAgdm/rndD+gUQeaGnmUShyXQ4wQNBNM\n5j1QQQxiqvtZnF1ahBP7vreIkh0AycQHTY4QMzs2PTslzIsj6TksIWOT8tfk\n/IF4\r\n=FUFg\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"6aa4f0d8a93920c6999b0c407d4c0a069026e165","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-8ac59cc-1625191292560_1625191339379_0.7448028787010048","host":"s3://npm-registry-packages"}},"1.0.1-canary-3a35ae8-1625450487402":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-3a35ae8-1625450487402","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-3a35ae8-1625450487402","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"126d7206522d7c9db2f7af74387cac06d53c9a94","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-3a35ae8-1625450487402.tgz","fileCount":8,"integrity":"sha512-Z1eJsxyTrBBsKL4yY6CjnKt/9Nc/6AU2QguSml1VmrFKG9L18vaktpN/TEu1D22I5TblI+J8R1BS5Kp0fr30Mw==","signatures":[{"sig":"MEYCIQDLoPg1VOv+Ip7jEXBshdc+XFfUl+uy8IJ3I1fEyWg9AwIhAMwjjjRPZlo2obkasH/ZsEVvRLpoZ/TA4YVxZRQnqmz1","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg4mgvCRA9TVsSAnZWagAAhREP/RNbARFOTaie9Exy9oA2\ndHuqjEZYke2MtTGKq4Gw9RxkLQMyw7RTtoMSaAx4x/c9kEesMdEeWXfxTMe1\nMFEJhzx6xjNMP4NHgTtjCV7LaRN5A6Nt2gbZRTDQjH7hqpRtzORrnqaelmju\nZgTbnGuhHKDgQhQY433sWuqStuY/wFUcp2oLdHgxD6OSKIXALZUkof85Ko1i\nZD9v2iH6FPxrMZM5cbWh+MndI9eJRbE9BBPreeZEyke22VHV6BQtqGWqf/Em\nG6eLunGjzXk7e+wx+iQNtf/b+KwOila262Dydp3VqcIpacYfIdcMyVuSQTxf\nJNaUSGw72KRaQ05pYKRRVSyY+x3+dvTwhr3KPR8RlQQq0ah6G1bIJfPsengg\nzIPOq8pzXzou2VQOCq/SSWw/87JGBJXO92LObgeknoYUi4qb2BIXcuFuewow\nCcrjngb9qgc9A7uQ4DnTv+x1740zG5VZcPuZTaCZHfAiCdTZaSv5/0eMc79D\n7Abjo4kT+RIfDsC+Yk7MzIQGKX5mOOzfqOGr5xnPvkKrI6HHyN7sTazpIc8E\ntVxk9SHbLj1tbrnVb4iZTSmmCMfgRqd1lXaeSoi9i7yao2/8Uko2LerPhJYV\n0KqjoUbgWHICp9Vv5y2xXr0GyfEBpamqBYGHrw0n8vWCOSqblwTMNIK9jNTy\nfDPO\r\n=ormI\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2effe59b78807bfb94ce8e3e534ecf61fae04eb0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-3a35ae8-1625450487402_1625450542601_0.05821679339690933","host":"s3://npm-registry-packages"}},"1.0.1-canary-316b40c-1625623277944":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-316b40c-1625623277944","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-316b40c-1625623277944","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"db32a79c9ed9e27b3ddd53fa1562fa467de98b22","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-316b40c-1625623277944.tgz","fileCount":8,"integrity":"sha512-cnw1nii94Xp78V3cgBH9ac8wawJ/z63zpu+YjUMoWstPReG3LNCzaEIWr1Cf+5H+XTVQKtrMuOB0TI4C0Sq//w==","signatures":[{"sig":"MEUCIDDcS0k1MMQadlxS0GDOVJwwi/yICyKBzAzVzrp2Wre8AiEAz8iHitNVv8IZPC18CVTNxMq9t5X5Hx5Nv9sKQf5tM2o=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg5QsiCRA9TVsSAnZWagAAepwP/RV54bROuqsMGmjlWFlj\nlZJtKfW9ndGGmw8E5QDEvtqfVok6KQlmu6vJes8gk3jJtcNphxWUIOrSmz4v\niVGtnrzBW0J0fMNIx+ZSCMrxV8GHkqBBh9LtXl4ye7CPv6ObTFD07Wf5G9JN\n1L8Sw3hFUvW+xptsNvhCMGOaorYdwjp2K5XZHesC2DQhgOwEsbU/HMmn0N9p\nU/wvfYtmKKlaE4dqJR9lsPFPzGIPe5fgrcTdaouuwEs6BtyXNh3FXJR5bv2U\nROi8QgXerSjOG2wGL68ejphRWIErGZ/gDULys+u1bOfriEkHCUzoPeGD09UW\nezN6Rm2edwuQQLpIGKAWzhHNmLcCPmffJFJXWik5MwPyH9AMNAWmQFl1Qc/Q\n8WDFLZIJqDM23f9LWxDA1rFhNnSQrMAWepEVTfkJ4EMc3x4rOCg7MUYg13nU\nWJAOpGRYftxo+r0/YMqoJK8n8l2lyFNcWNAlO7tLBDMk+UmJITOynrpf0JLj\nyB7Qr69NuNmeIrZDgO+fOlNFOyn625C5QJYOidSzBkM/Ir4S6kmPCfJh6iee\nknhbHrfvVTZEAVoQENuCOR9jaf6nFavsORS8CRWeS8TbelHwh5SouUqtw+jC\np8arsQa5KqUaxtiqS3BrpB+TsizKr1DdJw2rY9YiePA7wfLVoKKFbYQgc2Uo\n3Gux\r\n=QS1W\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"1cb68205f0861254e6bf7207915f73235622e6c2","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-316b40c-1625623277944_1625623330041_0.5142048443856182","host":"s3://npm-registry-packages"}},"1.0.1-canary-9a5082e-1625642848254":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-9a5082e-1625642848254","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-9a5082e-1625642848254","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"af96d4a2af1433c01a0689c1163bf2922aa1399a","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-9a5082e-1625642848254.tgz","fileCount":8,"integrity":"sha512-Mr8svlPbO2TLQ+JObfoMQVtyjcQ6Q46O5kbiwmRjvRmKZP4867H8qeMUQf3/KI9zbpVG2qokUuoy0sMxNsLtXQ==","signatures":[{"sig":"MEYCIQCO+/XUxE6LD7rZYYFKopJuDm5ncd1o77AGUHCVsetYEwIhAIvm9RsB9kQ9A3AyC2tH98DUFUspg/MPsvkyPMfbsesX","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg5VeSCRA9TVsSAnZWagAAVuIP/RPZMEjz8YT+pOwsN8t9\n4wszKZ6lSvWT00qQ4IQcYyJGx33BRfivTkhlRUymFHVJVi+YaqKzh7yYS4Gm\nFM/oTGUlLKybPeMAlPmtZed9+IZmx3rQHAuHJTxS+SiDAvZvlcsaOUTA51LG\nRN24cX9n2ztK+llAgRAn3vHo8VHnB31+CFATrHtQbrLZRI17I2aTddkXRvJs\nSo59p4rOVZ8cFYQvkqutEcWq+JIM3iRtxafjrWpiZuAhXja6qovh34eA7sdn\nehqFL0lH8jZy7cM6oW9BawSP6f7YZBKQxZD2AobelLG2OmBcAEkC7FkFZG1d\n0j8F0NAobd7sm3YkdZV4OjlfwWVVHGgzlALVfn0rXmq7DL7vhIg/AM06AKvb\nQdBcO+jC8zYzazwg+KE9sZH0cHQ19epIfQ74GG6eCmDmFf1Qn6UYrsqvDB7h\nV6hWIdLSf1kyYuDGc5ssKS8gn1mZrnQQvDeFpPurm4Y0LYjCnwsXYovbcvps\nWz3m2MtiBWwtgdX4tQAVpOlVaTBLnJwGpc9JjXB1ityVZsa0MqQsdkhY9ISe\n3dVsOuYGPX3ujQVWoBdWJ6wANuRNRTrE3lFQbHmNN6CNOzRb3q/hk6rMw618\nSpt071g9xj3ZmsRYAyzO3/REjF9sK6hkQ0IorrkC6wbpzR9xdeZ43e+eKhpQ\no5Lu\r\n=Euen\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"fe9455e3fa007abd202a0ea6361e6d93a8581698","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^27.0.6","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-9a5082e-1625642848254_1625642897624_0.09440656315137774","host":"s3://npm-registry-packages"}},"1.0.1-canary-9a5082e-1625709708360":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-9a5082e-1625709708360","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-9a5082e-1625709708360","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"32a20a938f9f9de4e4ce8e908952262f9a60a27e","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-9a5082e-1625709708360.tgz","fileCount":8,"integrity":"sha512-E8KN+61rPWtBVgDpXcAULSYgBsuRoHFeI3XVogm0nfjA1mlnkt8EdRgOA4ufpEGJJyiNYorkgWVGyvhPuFMuwQ==","signatures":[{"sig":"MEUCIFhZSBgls/tsd/xgBeMeuC6JQERmWqsWcdvxkUy7rs/bAiEAhq4dApk6D+whY7xqmGn6iNY6qjTq5LsHRj/FgnDPfvI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg5ly9CRA9TVsSAnZWagAAzOsQAJ4t/EDABHbbKDy/m2uU\nxA+ukc8EaAOxVty6ZWJOtkpBVBxIspW/eLspBy+j9u19iG4m9BUp2B4TNsOq\nO0xYOBKKe5kOJQ+Swqdlu4S11sbi4L9JBFTlgC0iiw7WkDdfdzHtWyYpJeaL\nUYDvQiMw/YbVPGgDBRPpWKmP/wCiZ2XcAokaAk8bqnSnbPNtOOphAdAvIUf1\nSPWVUTtpnJWeu1GcP5jFYKFijoydg9TPLJjfzPWEIT5C+w6ErRmKHarDG8IR\nhM3YwAB8gFVS3jxPC82rofX4LqhADmCFN3tNFPSyeA3dRofSfRBdbYYiao2j\nZWFGXqE+u9E1rK1UAaTp2+e1P7l+0spyFB57kysVM7av8xqr78QjYJchvvHj\nmOVQRJlc/ZDahRU3H8IUcln6o8RwBliTHU1GUL2pvVblr/aNwMBrjprV80XW\n9VNxGzy55ypT/j5NaiRhig8y1IL0gg3SzjSmDCC3cPxvEtqckLSRgBP+hrv/\nafWbmiPZpmKw4lASBTBP1HwIeMbdnVYsYx5nXvC/IK57YtEJGcfD8fJXQjV6\n2OSW9Xpyzk7uzFlpaWi7wZPpT8OeK1p3B+1qX3diUHMsaL1bpofS6ZxeG7NY\nudzjv3lMH7t+zg5mHKX5r1ETO5T5rrLBG4HDzGhH6fuFIcDbD5EKP8Ve1wZj\nlrLz\r\n=PHtM\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4556507faf0604ddad695897645459c365653d97","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-9a5082e-1625709708360_1625709756445_0.5576855722853771","host":"s3://npm-registry-packages"}},"1.0.1-canary-1a2439b-1626055312419":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-1a2439b-1626055312419","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-1a2439b-1626055312419","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"701b73f2c847658ecacff5efc5025714457c9009","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-1a2439b-1626055312419.tgz","fileCount":8,"integrity":"sha512-a5hGESuPzDcJOOcUdJnH4EuQvCiz1MHuP09PhNamaNKwFUQQofzNTTMLYLOmbM7plyDB0xaDPou1q/KdwGhHuQ==","signatures":[{"sig":"MEQCIAm5nJBbxuzXUuo8e7rMb0Ly+2CqriAqi6dgL1YpHIONAiADRd1JieFW6CKkhAYXOArSbz3IgoXJa5uB3XdI4RGjNA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg66LBCRA9TVsSAnZWagAAQ2wQAKKeeT0zPC9PtQ9BKWk1\nvThBtqbmpLUWNFyNrJ5+hJe8fHtgBpSbum0TvbQF4yACVrdfOvLVQSHLvq8w\nds01oeA2wmX0bXduEMCA5QnO48dpnuTe9Mu7Hbd2KLcj5TJZazVuaqpMdqpo\nvskt5bAap6u+rkNCGpKT3H2F2QbKTq/ra6Zg8dLHspNMw0UvG5KpkU63lofv\n7hwiXiIrjtwGIuwM8a0siPj30kutwyH3KlRgTVhxtx23buYWJcCNutPFJJpE\n1ikgBuOnfXEN5N4feKWLg6D/nIR4TVuwfcc2oZmKK57W3Q0lQMY4jZgm1pf+\nAy2T1k1RTJTsxJM5xyXTO2faOQpAPJfVhmRGaGOfgiRcLeOrhbA8oy+MTf4e\nZu0HrO2ATUA+RaaWdT/anBxQWGvD+Z+XTP1wjBjWaPrcUcm0V4xp3hucDd7o\nr3E+AhgLnddpmadU6R70een3tU4KVr9ytcSgRtoB0nlDKDKVFEqzPwp46w+W\nco+MiwXy61UkWCluswRzbCh4i/kiw1T1GZOuqWmcbFduwnGFy5zVEuNp/TtS\nARh8JpJpPkP2E2fVH1hq47TcBJHTtfyqQ8saRfpSDesiHBlNfZIOggSnEHC6\nBEEpH+Zimj4PgzdhYJx0SSCAYROVhKP9mH2LCMiuDRTKHPE8xdxvDUc8Lv2h\n6+s2\r\n=X3/G\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"22232dc27237912cd9e7e5eb4c90445eba0ca3f1","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-1a2439b-1626055312419_1626055360433_0.025439101574205036","host":"s3://npm-registry-packages"}},"1.0.1-canary-d8a03f2-1626400898820":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-d8a03f2-1626400898820","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-d8a03f2-1626400898820","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"4b3c54e7b63d7e8f16c1dca67c6ea6ea4464d5fc","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-d8a03f2-1626400898820.tgz","fileCount":8,"integrity":"sha512-IPYnzR0n+Lqpb746C0q+au84hLevWGGhDplxOLtfU0aaZoBrK45wC1WuIVEFi9zitcc1ruASdwWp0b/isb6eRA==","signatures":[{"sig":"MEUCIQDQNQDQC65118sIgt3UMKA7Pwdz3aP5KogHJ15la8I5DgIgSUrHAoH3JuyCQhjBUi24UNS3/tJtlbbbp+Qa0wgdxlk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg8Oi1CRA9TVsSAnZWagAAiQsQAJmC4mf2PlAaAYfvWCIk\ni0qD2k2008JERlHD/zh6JLDESiOW71on07nJ7rNw0VR4l2o1+KjU+p8Snw4U\ngIJeGkQF6XH0/Tcd8H5tYH6MI3hlWPlwCl05DjaR+Z0HDflpoPdRDiaoMLC9\nR8sYXj6qYcYhSJkAtQifVDWjK+W2FI0M094x8d815SyvqUMucdClWbcWNLs2\ny2kBwBhZKg/9jBkfMMoHI3HjOCSIHT/Pu7Rev7PorX9PPKvljHnhNM/Zgpco\ne0/HLL2lp7K7CTZ6F+nbi6x22MSVZW2/09rVCi1LQS5DPrcbibP5bhJwLljq\nUtkVJtpa6Ka9ebElla+mHn+ZtLQLJpew59dmXo/wtKqhMVohuNo+RmxaZCmp\njcd0Ho2WS34b24BWUQW/GbjdVKo8gdM/ZvQNk2HU81cEtFAxrI9ViMgdSBd1\nEcWFj4xZCZfIkilgSSebixCmjtDVgaaPzzPpqnxkVnw6brj/Ruh9V7Nk2DrP\npXOnuUScFoqcFTQrDrf5BBFrVzM9ey6n6R07r/lBsarPckqRmETuNGQgw2JZ\n2cUM4mqQRN4tp55LokqXbcK6DwsZksREsTHcj5BadrhaTrnnyNprzi/wnwAt\n48cKz3DyO+CSfBjhRuLP4H1PwwK8uKcjfcs59booT+UNbF8T8pssyyOvgNc7\nYDlY\r\n=poNq\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"708dbd9bf00c3897ca7c67f59d52672c0f3b9403","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-d8a03f2-1626400898820_1626400949340_0.19489134356341187","host":"s3://npm-registry-packages"}},"1.0.1-canary-d8a03f2-1626400909081":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-d8a03f2-1626400909081","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-d8a03f2-1626400909081","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f87acaea5e60404dd152f716a0b5e8232b4a23cb","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-d8a03f2-1626400909081.tgz","fileCount":8,"integrity":"sha512-1d2PTehEER1YNIaUw022VvclO4w5CbO9vqaAg6nG6eK+1r/lEOyWzXKE2exy7gHsF8fIZS8eIe3G0C9l8HSkcA==","signatures":[{"sig":"MEUCIQDuEZCy5uA3GoMOVSGqH48AHynu2x6T1eWxadFh6PqRNgIgKJykr4XIBs5PCmvgLTtbUUaQ45gXtbwpVkMKv3DtqZI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg8OjBCRA9TVsSAnZWagAAXzgP/RVJyN2IdzE/7pSteo0t\nJaLD1Y4b1ol0c7LQJR/yWVr0N4Vnyp58j5VR9dmeIVjS8aOp4q2Kh5/lSaNY\nhLSmMhQQevR+/Sw0+QNElcOHLEqnh54BVjjP9foksVkd/JET7nX77wBimFkT\ncklpnuGLrwGSMeJcdsAou0FSSsJPustLqgDmpZO7UeaHA0r3QG3EB0cfMUeV\nZdcwPugoSYWDayr+OPw4AWJ3wGzypPME4m7YtWNoZlVmP3jDC04UeuLCqyRq\nvpQoVk9OwejwbqEt0s0ZnmgzcIUG/W0KU3+W978Urga9mUFjN5SSK6IXQbX1\nlM5T/R5sgQi+MwnBUnFnoO4p4/0Bmxd6e00mZ9NeQep4Jqt/JhANNXbllSKW\n+/K79LJ/QouVYLHT7Vj7GAXXUtofq5YKj6oXz4oAjyRv5ehucME846Samk7y\nRGzAaAzvUayBKC/Et7UugbJJ8E7N4orzCzcS/v5dWPn87VbcpB4h8eMF06fE\nYF8WtnLWBfVzfh9t46XjFsUxPsL6Zhxhmmtsne094I0Cr6Chjjqr1j3d+JS8\n6NfKBJ9aXHUmCYgpqlUSNak9/uW3rUiGLSEMPHUvYnRObRGXRa5TWcqP+KsA\nKk63oG6t133hzN/TUqG0+Sgd4D2uXFIjGzXMLvxKACeJ6wBUgUWcVa+ZRcqg\n4xVu\r\n=t+jy\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b5701ab80eb9b27e78d4aa6aa7917fda088228d2","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-d8a03f2-1626400909081_1626400961588_0.8011772781430795","host":"s3://npm-registry-packages"}},"1.0.1-canary-2fb4fd2-1626660476713":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-2fb4fd2-1626660476713","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-2fb4fd2-1626660476713","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"74889a0efcf5b02302150920854928ee44490e12","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-2fb4fd2-1626660476713.tgz","fileCount":8,"integrity":"sha512-x2M4ewr9W74sE2yWrryovYuNfch1O4Ym7wcZJubJ5uEFPr/AZOEjqDAAdz9WWvVagatNwJXaOP4PoscyYcnRLA==","signatures":[{"sig":"MEUCICYKc9yB3QqNUSm0WhdJvq2m11qtC9gdJHWKIJk0eJ3QAiEAwol6KW9EtoLGMqNTMFLI2kkfs/W8UaSGm/YpiXFmb7g=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg9N6uCRA9TVsSAnZWagAAI4sP/Aq3VAWq8ebMW4XsJUNL\nraZQAL9j//EsA8FVSIv8lpl9dxsjOvIHHLTZc/wIeLAWgimVehDpTzwWLQFc\nOvxD1mRN5HKHYfMxBeykbfJi30kTvSv/oGp/7Ry1mqQCqs4slshUk9eHtH65\n7eaIssGPAcAU8iIGrsvl1MaL6KvMrphJ1qXu2cUft2QqH43f62TEwzzpYOtm\nW4Fa2TNZyB7j7w9Yj5tBEilnFk4DYzlXnTDjWVbJS+KqZuSe5rYQ5Hk2omUk\nKxRpweQsZ6V+3xAvAxzZ5o06pJCbIUaQb8UTVS7NvtVDob1JySnBDEo2dMMU\nikjos09u5n7QWit/VABd0MjOO3UTRJalbiMMSCpQ4PsSOplNtcf0Gjq1XMZi\nrwtX1w7vKX2afwQM84r1XglOk1e72OSbRFlbIHyZDa4A+N1gOEKPIzb7swUd\nqZHH1B7/Y6zt5cBR5Rza2XAJMwTY2XredLBixR2uT3VRkDqCiv/N8eGx2Z3R\ngR08TMZPpJ61qPPu9QON8bQF388FVACSDlRivv+puvDxm1ZqRRmm96zNZb8S\npe7hN6iroSA0efarhop5Dvveu8Yz6uEWicKaI1/Fv2ZTekLXfc1f15qXwZjH\nxjIHm5tG9YXunzkXkhYTKopwJZ9DG36rO29ALd9bonMOSgTWBarP3mW+wCDQ\n00Qj\r\n=Wb9N\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ce7a5bc1e71d0eb8777ac97bf1c7a4f8e90016fd","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-2fb4fd2-1626660476713_1626660526214_0.12768014674132022","host":"s3://npm-registry-packages"}},"1.0.1-canary-d3ea5cf-1626919299486":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-d3ea5cf-1626919299486","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-d3ea5cf-1626919299486","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"086b5209d227122b23fa9564a9110f3d03e95e28","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-d3ea5cf-1626919299486.tgz","fileCount":8,"integrity":"sha512-llUlhXky8hYiPxLPeumtlad1FJlUpYwXZAsYm1ZLVA5aFlaCR4CQFk5mzo5Rcpowk7ihdt/+Q6xhMsbXF4MZ7g==","signatures":[{"sig":"MEUCIQD7iFPn3lqEAEA9af6ekj1jybwR8lkkOJ7De98LC6yWlQIgPl1FbD3Qzy1gABxvvB75cv42jqEYWIzJjyq1NEao3Pc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg+NG0CRA9TVsSAnZWagAAlCsP/jrshAvOkPmoEa2o8Sqb\nvQqfHl7MTSg2ArvPcz/IMVl/3ENYuAsmxDtgeSkO4mmB/lCvIDnTFvn11PKB\nYOqMNgYEaOSs5PQrdsw0z8NsHLgJa6N4v88cadimmFmyJaTEug9BeFIz8qdM\nyBnRwOgruJb4heNwwgDhxYVaWT+QDbaTVEO5KexIOMb7CXwnCW/YLd+Ce2b0\nIodK/dqjy2G/m3u/uBG3eZL5YxC3aV1RK8zzCvfXY1KvgKtBjIE/2e5T6fQU\n4l6wUU5DsUzvjWhE4tcDMAphPvdAQZXNw1r9zcamrGB8CLhs0VSu/yGay2PF\ndZV5+sr2jTL3GV9xD2iR7tR7iECucbv501cYxqKVx9sxQ6riq35cOCKJePTF\nVB6EfgxSabl1//fcIz1YLde0xPL5ZMQgil5okJLEBW7J9URwtt0rJHkGi927\nz6PFkg7IbjlD4bF/X5mYI+X2PMkCAxfBn8ykSvksQBVTcDgwXK/bJouj+W36\nZnxKoVnza7EHx3i8tcdZ+DitnQwl0N0XPksJh1l2BaNg0xiGJO/nwufMgl8P\niATKDoruMdmwl6PD3NYIwmri7dfXilf9lfQWOdqvybm7qgvCuYfKSLzQhZd2\nFhhGLsWlVYBGnAjdPx1CrlAxvSlGg6qpkBJFqH1Ur/cW9uk7pjJpllyPsy3S\nLqWC\r\n=4hTI\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"258e39cf059e96fffa113db19cc3773ed7ddb502","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-d3ea5cf-1626919299486_1626919348493_0.6421492685339039","host":"s3://npm-registry-packages"}},"1.0.1-canary-a8c0b11-1627264897950":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-a8c0b11-1627264897950","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-a8c0b11-1627264897950","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c1bb5780476f7428f1d86b59314fbea2af668064","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-a8c0b11-1627264897950.tgz","fileCount":8,"integrity":"sha512-7GeZu/nytuLx+aGhyHHIsWRVIIXUqmERTayGL5OjZ62SK16eZxJZFvCR3n78iEnMZUFToCSrfRiEoBY+EYj/lg==","signatures":[{"sig":"MEQCIDAjHPQ3loCz9WbOxk5SVCSEkiMV4lYiRUcHhUe6baqwAiAPCNDP9jmQ5864HC9pcXlufboS6fdVUSkj+EKn/VcHWQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg/he5CRA9TVsSAnZWagAAWIsP/3J//b9oC4aJ0C8YZqQa\nJNJh+Tm1SFJOSZyjSS49Xmgw0bKfMZ61kvjnUQUfqkvaURORVTq7W4Wxj0+Q\ncJPaibHe3+35zdJDSwE8AzvTNwMoRDmfb9/wDPDfB21MWUScp1klm72RnY3o\nEzEY3/s/oV8rcyMQKxWDt8UJTA+y6ahWjKqMRZ8P0/0uJjeGvS4nqed3+e72\n29vB8A2g81LAC7NzMDAuN/2uBytjpJDrw20EikaA7jY6s+5R7yha0M9eNm49\nfpTYo++7kFLvyNmWgt6V9SU09ZFF/VauwrxQ1ttt9eLpvxTX0LUG5NwsGJwD\njsvD33nv+DffhFNSyThgggHOi4bE4QYnzSsz0OmNFYrzXNHXs2Ufv3laeSUO\nZdY1V1E64h98MjmTGZ7UXnEZVJfGV3u/Fw3NANZsfJTPQXSgNBqE7arfrI0X\n5QwEjIA5MfKCjm7xiAQwwH3qVI5NieBkrjDWOESU/PSZ7BS8hi3/7QQKJccn\n3Hk6jd1quDFHUFWJpNTs03xb8r0jUL8Q0kfyZ1SgJN1KpGfvINgxItuSUvw3\nSpTXtjr6s0JKzLZV6Noa9JjWh0t6WZWCYuHjBAYjOWnxwEi5gi2ZP7XERB+e\npFQ5028cS+sGWnVD7QTF7j8sI9NC0AkaulsffgGuZIrVD95S5v7GAkVwKpl6\nugeA\r\n=Cx8k\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"89ece5027379428b46cb8adac25a98859e1f55a1","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-a8c0b11-1627264897950_1627264953811_0.37597558850041635","host":"s3://npm-registry-packages"}},"1.0.1-canary-1ea1131-1627351299847":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-1ea1131-1627351299847","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-1ea1131-1627351299847","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"4d90d47aeb7c3fdaafbf8d49bbc2ebdecff9e9d9","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-1ea1131-1627351299847.tgz","fileCount":8,"integrity":"sha512-to0dtKnByKyY4CG0FuriirJBxV79XIlYQZORTmhLmdOMJqcw887yu5gvGKlG9asHGbnGnCEaA2tdE3bV8orjJQ==","signatures":[{"sig":"MEYCIQCMvpGw62z0XFobsPfU05qUApZRnQ9Br+RX4I3Ux13MtAIhAK4jh+77v460bH2FhF7JT/XMgOQ6mfKEXjhVdLJpUWO6","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg/2lECRA9TVsSAnZWagAATJsP/2zf5bg1hw1PzS99mV0T\nxQG+R2xmL4fPdVAiprOq15hUvJJ89IjAAyJVU0alZX6dUA7t5h+oSLfVRFn0\nkWhzSHENfGj8cRKkRf9TIcy1jFiEPQ+HtNyh5NlBQcJI05TmlhJDy0R23u7A\nelrYdYsWUg53pv5VY24koM0CIPbsu9KCJQ75tp/ZSHumQU0vBcEsHUZcfoOY\n7/JrrmGJS3UVNZPGTMyUC0G2DSNHtEfaf+GQw1A7/YN1AOd65uDq7fcP45FY\nPZ56xLyehKWO8fyM4pHUrP68XE5PRMO3Qcz9SimV2s9A2A9gmUG4+PjNr/Zo\n0yihWoop8snJNAVvkYrihqwjwg82n1PNjrnoyNs3aurB/kOQqcUpE52QuMMm\n5iCodysvHCcAh7qjwCAH/gY83RlgULmYMMizSPJdnuLPIzPQH+wDZ0BQcoX6\nO6KkgUfB1u9cWayhl8gKTsHHDIz0bnZ2FHbcs5LnTVv7Pw05J3lU42sPeX4r\n4IN+nlU8Gs0vNfFydRE06ROeU/K00asjGx+UcnMmxTVcdfEXcEV/DX/C9GR3\nnib2Q0C4nQbyOXdQanygQZsHlDF9mag6CD/a1vdamSvv/L9oBcaxz3dZAHKC\nN7jydObCD4MctwB1sxJi+9rmc9qW9paVJq04BrrTag0eRWfxiXE8Ptb7Zh+F\nc4s3\r\n=x5D8\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"e324eb904539c277850a86cf0198817bd837d8cc","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-1ea1131-1627351299847_1627351364624_0.5834334690797538","host":"s3://npm-registry-packages"}},"1.0.1-canary-6e7a4cb-1627524096338":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-6e7a4cb-1627524096338","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-6e7a4cb-1627524096338","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ce8d9dd9429a0c6b55b5df2a32ecfaa9e16b0859","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-6e7a4cb-1627524096338.tgz","fileCount":8,"integrity":"sha512-UBUdyUzITTB5teSvI9EAH5qxRLrHl2QmFgd5N/F/dYVwiVJWEjVl7iQLzMe2mhMrggnW4pEAbUnt/eHQTNWq6w==","signatures":[{"sig":"MEUCIQC6FJ5kRJA891gXiNjqzVL6MNDaK1UrN77yQPxdkW+XewIgShoEn+olY1h4e3/acrpxf3YaeTWdBHq18zZ0I/206Gk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhAgw3CRA9TVsSAnZWagAA4UUQAJKJ+hIJBoiY+CWCx0Xe\n8vZzr4rrokIlGNVUeWWO32zxwwEWdBRVfUb2Bc/V7CmA1LSNYbjLwIfBPpZ0\nL9fwwPTdAnl2F/pp1S3KnwTR1LI9QlQ74ZyGwSgI3+315BDyiYrbop9x0gdi\nD+UoV0gqqIYCxvnbf4vCo4J/MyQ5JHFZp0uwgXcgZjXcqPtLTbunrsCDUEHw\nCPlju88Gog0hGZlxg7aQwyB99V4XFq9wH/6VMGKKL34+RYIRpwikQ2/6OhJe\nQ5WtDsg3RPlO9fAoj0RBW12fYHlwyu+WJDESZcccCGSGX57TLSIf54G1GYkk\n4wdmBse4aif/v+hceogicAry8UzIDLFVJ2JQg+jacxekXM+soEordMo9y3AW\nbEiyfz5KZBK5/fJGPavtaN6AqSiYzoyjhPd6sltMs2N7MFY3wOPTaOq2CI2j\nmd4dcDtiBU5yfaYdsQQxXksYWmMVKAirhpn2uJ/I/+JV7fZWxg++ykteE8HP\nn98udmWHZjTxcHiqTG85aIz/7OWXCrtUtpawi1NPCHmjerFoRL0/+T6DOtKX\ndU8mzQECgjJZkeBHu9pTNhTsOWCG4Op2Wf/FRP2LT+55Wd2d5q/DHL6oV+5f\nTFZ663u3xyRQd6bukixeZfAs4KA2wROwslMRGV6vslBuq46dPebpaxTJa2bW\nu0pI\r\n=Wf0Y\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"eb6007331d0fcf3c0866d1e14a5d3618c77cb586","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-6e7a4cb-1627524096338_1627524151645_0.1433279636062923","host":"s3://npm-registry-packages"}},"1.0.1-canary-2c88a36-1627610493388":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-2c88a36-1627610493388","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-2c88a36-1627610493388","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"16f6d0cf8b22a6f6ec40450477b256da77579060","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-2c88a36-1627610493388.tgz","fileCount":8,"integrity":"sha512-gMMxxUVvcaj+ucd92QJPAi8tz9hxTvuuk2wAcraFfk6NrGVW8og7nNHJXMFOvJf3Yu7WYX8yytZ9Zvq/ynMMjg==","signatures":[{"sig":"MEQCIBo96AGKdaOvYMR6Lkdb65fEQleX2bRNOVl4ZNhw3ZGCAiBK+Tz73MA/34r3+j5xUWB4ZllECYpzINT/Nh/LIpjLTg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhA12pCRA9TVsSAnZWagAAKkkP/iqFkEQB2YH7aBPO2Kcf\nSKCZ5R7xsb+QFPVSNZrO3SfbrOvYBI4ZIhror0sYfqUKvZbENqw/z35OxDZZ\nPcu8nd6H1eriD2sGS4xi7QYJPLKp5NGEaq9WbM+T0U1NiwyO8YirTcGyqxeF\nn47geIlzOKUuBkKXiS4OnPPCPa1UkXANurT7RnUQqr8D3F4WUinpkdM5PsXU\nIW6lW5DprgeR1YzEFPRjcIeMk23wbfgHwN5G8lbjTLGx8cHTLoMBMwFT3H3C\nRXrN1vIVsfdyfa9nF14+rtiO3Z8QRSK6Xoe4CHy9NDVAALb78McE2KVA+nZV\nqwQLVtJ6j9tXJLP7+V4b6ebCKb6dvfA5m5s8z4FNdNLkjcLpgE3UV2P7uFkZ\n3HTUKMPUV5v34FkT2jzilmo0MJnj9rZZVvQw2x2kMyia3k1UizdTfqxamzL8\n/WQiFw5A2zBPmNP3ZYTda6WxQ+a2WqR5EVvmW5y7AmowzMQpCovyYkS4V0Fi\nkhwdRAZww/HtSj3kxbjOIfcgFmCbBk3vkDrzWGOb8v4n3q310SRZvrApW2Mb\nRlaEneIgcPWK6vQJbsCT1JvlQiBLVsBAhdIW5RKHgvzv1ZShzQ4W2YJZacPM\nyYbPPCpQ2e95YSbKbOvjO/qWleL7o2dGquh072za/bdV4J00Z1v2aBEHDhZ4\nGlhJ\r\n=e5UK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9ec6fc7e3e14b03f213047515df1964a8fabb05e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-2c88a36-1627610493388_1627610537234_0.6154619704763797","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1627869696548":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1627869696548","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1627869696548","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f1397815fd6c9a412583d177219b8e7635be32e3","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1627869696548.tgz","fileCount":8,"integrity":"sha512-/sb3/sPK0ctavCrW+/ot26jZ6iLwD9EWcdeQqnYzRwDuVWGAaV9zEvB1tnnLoGfrC2eUDEOUYwvzDbkm6VlemA==","signatures":[{"sig":"MEQCIAHgU1fwjKqtfCPjgSEJW5Ui1iElNwMp9sT0nRGs3sLDAiAcr79pnYL40m4lC68/lUBSvOdyiqfTEG+3inwZYAiXYA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhB1I4CRA9TVsSAnZWagAAowUQAKIbBCkt0SOnZlC3/QrB\nMgr3gxwKzFp8DMtsa190PwuiwExUat+9DcAjGY3uf+TxhVRHuNAAX/gkpJrU\neuDmpk91+oLqc/0p7w5LBHdxH3Gn9PlaU5lIdZKwKIKzQmB4vkIzZpUSXGRn\nTdamiGHKIFkyF4c+dlDJIqI7NaNCaN++GlxQVjSb6UP4gKFzNQzPKPtzdMIM\nGgdJAabkpphV1NAiIMfSjv+ZlZZk4ZuUdDWhOhlr9eeTb+iC3equEK8DhMbw\nX5yJkmeldM2DytkumeAe1wpTkjW6WNENWdVMjOA6c12hpRkFC+enS9Hbi1Rr\nT5wACHuZnx0epSi4cggzGvBB9ikttdEXMcJ7KZDeRaUkeRKEhx6b6WKOiGmd\nvhnuPHrB1KD8KQedL7VG7blxOQOh/Hgc6N6Jmvo56lhG3uHRQyc84g+ItNTv\nmi9GcAu/kq70yOhdKHxkd6aVRs0oRd05ado2YMGWXU4bLyMehjWOTUlkaOyT\n3o+ZwVv+urxsjU4RHD54fen+EnkZt2YU3ySKJWY5J5Yl3TEUrgYTUzGic+hS\nDjmuxAN/6xlXNKhMas9VObOjWwn3sVKrGyd4qRR6T6Si9/zhCeXsKKbH5L7M\nwiQ14+OzOnczd8Zh0rcOK0ie117r3sYMlWxyLdtIANgOH2qTtXKG71DITVxs\nryts\r\n=QLes\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"503f61021375f7ce94928f09bf427080da17e328","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^20.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1627869696548_1627869751814_0.420779989049886","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1627869711930":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1627869711930","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1627869711930","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"332d702c2356eeac6313ad98a4aa60f4ab8b25b1","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1627869711930.tgz","fileCount":8,"integrity":"sha512-xApfUbH0oBz/zXNIx9onpKb2AjPzqREVw+ZvVWKXw993BWvhMN3ShmTZdsI4rvZr5snsHbO3r4nopea93FY3+w==","signatures":[{"sig":"MEUCICPA4mNhFyhqtost5zKu0vlPDwnagydO7fCB7F7kfQ/cAiEAiO/5u0EKuI7MpGnR6poUxg6gqazu6HNbIta0+20nQoQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhB1JBCRA9TVsSAnZWagAAF3cQAIQENw61S1TFjSVaLhaK\nbDPlo9Ic3q7WT7J1ev6bSbIwX0aSptm9RopvXzhIEKvKhEyO+6n6UXJP9nu2\nI4+vnkSezokqWqwYwN6SrG5EJOvwr3WW+K/8ScXd9xvJq6Xx0lNueKsHQn3h\nyZ6VbVDjjodMBoaG1+FzkcA3t4VnUo1nsFnCULdNB7q/URtzXEbXKY++Jq0W\nO4PS1PJm56Jm9qAaHbf7IHY5o6TADyTPuDRo7uEsBTEUmXCUO0GhjXoqLCZ9\nLSw/a6FYaJP8fCaG9INdc+7TLmjr6ZtBxGP5ef7mggwfWFzPahiWCCyp5wTx\nv2T0yFdTXSz6agjUWDYw7+WTlUfpM6y/D4hLXe/Tp3GesKblEd5pyMU5C0xC\niARA2SaeLooaVLalTMotourd/bpAC9Fj+fMgwzez1qzupxov6xnH7Sc7dZZR\nUV7XU33J9WFv/pYycrW3Yr94a6I/wGmFNuuYazDqSd4megOLIAzz1JpA87Fi\nmkGO+pLv26ocm8wUrOCpEX7scqQHzsUm7WFn6Gpzum5GryVZx1Pd3bUgYdML\nz8NhhJSSPMNU/Mm86CvxXmRloKAnZ/34ymqbZtzmwux2+r1Ea+SqCsJb5dSs\nMk9ngf+OzT4HT4oEWnr/2JjVOPLc1R4C1cRbKEcyFvbdDoHmiZTIVBjzYBHY\nMtZy\r\n=JtiR\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"c11b92626190cda13b9ea5ae7f9a1d17e34487b7","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1627869711930_1627869761329_0.37348776545481344","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1627869720614":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1627869720614","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1627869720614","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b984610365a03fc24d7f6a85c45dd9597171fb68","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1627869720614.tgz","fileCount":8,"integrity":"sha512-ynveuI0+Yt8B9duxgZtdlPlfCRr9z7OyC3TGGBn2wJfesZNA/8JlxsGa6an1wCBWopcMIHpTXZp5BfvaNphFKw==","signatures":[{"sig":"MEUCIQDSZawoH21FNytcyO1Acbf5ftaB7CDHnpd7Jzi64NpgRgIgVkNmWz0GjZvrd+79tJNTjI9HMHsHmpWQ8GL2A3GIUWI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhB1JOCRA9TVsSAnZWagAAtc4P/2+DkkRCvrYvpK86ZbfY\nEjgt5hVfeMBmngh1dGiZtawpSMMLEPBwl/sXypd+2CcGbY9ugJJaezAhxzcM\nn+zxR16rHaIfCj8FTaczKXP2MaPDEWV8ovxH9H5UjNxewpsChPY4b6W/QBfK\n36ei3eoVqWQdg1O69lgDYI+QWXwZe9REcdzGV5Wbc01Prs1/0ZTyio4wk3CF\nobbC5O//dmOCZvAvZqWOP/s8ZQoEy1SAbjaC7tSwF8rPlw32ezf8VV7es2Q4\nAes4IRnh94cRoc43aoN/nv86YdDlJT3kx2PUzsL05SaEf5nHeCmhr0QPxxcb\naYoAZlXRDU7Ermn8Jybf1a76NWsCz2UGVaTsYzDyJeWwozhS28qnLKBKPtMg\nLQ1Lluqn21TMB4/DhpZ/BO4h2RfsBjy59DAEvyOthsQPo4r1F86O5puM+3Cn\nBJkAJsoBDVj8mYXWqm1qGHDyfW1s45IuShW6QxqW2kcyhjA4TsvM8+NDqJO+\nyXhRIdtAmbxliZP70K5xQeA+xDevyAzczOkGGO7aDT39yeNj2FLVtlc602+c\nOkHObDersPzkrNLxjM0SvhHNS89j7svYrnQMRj/Qi44yzF/NIjV6rCwx7Dkt\n4PAvu69uw4Tb+iWZnulE98mdAYCqXguUHkrRZZ40ERsaHtKjmTpdM8eUKDGr\n85ra\r\n=zkuc\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"1ed0af01d3f2509fd3d492ca15d5a772f6d1bb1c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1627869720614_1627869774306_0.42569438878360333","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1628215314944":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1628215314944","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1628215314944","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"084d153b2912e17726001ec629a5e0c8dbfb39fc","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1628215314944.tgz","fileCount":8,"integrity":"sha512-06va8NW2wWborGo0CGEYdhq7+lNn1DnWvno5BL02ybkxKe/NiDRuax8XfBdVHZ4XfnNbRVvE8TAj4Rp47kpkKA==","signatures":[{"sig":"MEQCIB5pIF9YZYeOkqVPnILTcpnNZKl/h+T5/qTl0FbDQjF1AiBJQUSjSd7inQC00011u5riBokvvy2ElaBk0UO3r+LSRA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhDJhCCRA9TVsSAnZWagAAu24P/jyJiLFtre6l26OxCCoN\nuy/TBdA8/QJHVDZCjM6+2rosZndZBNdoIhE9bsjAP3o+WUlVzRp5ozzUwPwL\nhu/lRQaoK0kuvfNx59vgtNpWwT6LfMr8z02/rqh0PvDcJ/hBw9BO4y/r3lnr\nJIUA8bhJ+vFPxHrCcj5bqXWMynWp2U9CCdviCFmy9AjOPK9CyiURYyoIQkXg\nAbG2EY1Jzy7L6Fv6Y7CibDR7IWrny2vb5iWQBJZTANGk28+X3Iy+f+OeaEj6\nmcmB2XJgbvu1CnTjZX/fyM4Uq3t0iht+LYZtlUdNCMJ1T2btjS4HuubpnlDs\n6b2Wn+2OfSiexqZ30/x4HJci2P65LxzlEq3W0UF8juClST67rSTg8YyJ8g2z\nd1qRuIY28jWO7p84l6nOCx5qK/X2sRibrgRnk6SysBtQTJb71oYcmIcMJxbn\nhhDz+S/CFMJ/V49jV5AMSjtEU0pjEVcslYMcp0YBhkDGfvyGiq8pzqgQ3GVr\nC9YpR0Z8TxRe8Xw/jk+9w5n00l6BaBbGqHjShBxfVD5g4hRrRnmDYEypWbDD\n14R5NcIwHJDWNeCx/hbUjDrWW6eunfwCmKj2oecHsnF1owERGf8QfpMd2J4X\nGrOymVM6aIsuk3wBiRQ9NG8pnwOaDgydmoUQwPehEXrk3Gf0bk86Z30OAhmi\ngYKN\r\n=xREo\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"3b7c4095822353d430f3873f31b89644e3c69f09","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1628215314944_1628215362334_0.06338955875397612","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1628474496337":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1628474496337","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1628474496337","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"9f5d6a3de6a9a82ec4c7795927f6cd9129843887","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1628474496337.tgz","fileCount":8,"integrity":"sha512-bChRQJ8xdDkavFV6T2eBPdPfP3fUgOT3LprxpZJaSNxFhv9Avzm2VJIth8b0qYWlPFK6RiMkmCglY2rdv7vWtw==","signatures":[{"sig":"MEUCIHHi6dZxbUZIjhwryl67A9qmMF/usgGBNTY++phI2OIRAiEA5MaKao+YhhJKhE1ZjrL7Dk25jr0OsnKAFwMOB83KFmQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhEIyzCRA9TVsSAnZWagAA9KMP/2Xrj1+pKVB3vVn2AsFy\nogbxvys1weyxNH5ZkoNrjFeeUZBjixLlRDhdjBqYJqD53gegkAYFjUQ7oAXI\nYCcAS3btOLqxX4B3JQoSB8C564QRnBf3WGMaQlv+iWRSKTTxtKOmTyT6SGVu\nHvv5djMgGfVWeUEROz7mjLJIVM8OUryn6jBuIHgguATQvweEULkpsMoTAX5L\ns0QagoBRfMGwsS0VO5qPWHwFlqLQUIY95Siq99Uvrwiqn84788lW1y1HpYqy\njLvKTXTK9D2WoChtcCqL5q0lj4bDsHyuE35vMMmeNqyhc3GhldSQpM36E39G\nF++ryGY253vv67+HXuvVvbSG+xmyQTxuPG0Rz+8J2KRL7+H/VV2Nvy89tAru\n7y0hyKILXiZa02zDa9xscUTphF9CiM37yoZC/0Ewe4xAwoazFNQjVffezZ9v\nQKru7VApPAv5CVfkIsXFE3t2pSPu/XxFmO3Udk8b479Z7CTMQA6ZgGoNdqjc\n1QFuRYEp50r9qVM+DbVy7RQqXChz4qfyVJFa6Z7S6XeTSMuFlggx9pasOZ+c\nxNma9TxV9JoPBB4S+CBsPm1Z3yrKaHDS3oPWLJtsyj574m2ppTC9jtcQdhiN\nCCUgaSPBFrEH3K79xFaibpkgX7+Eaa69pvoS8DrR4bi/AfIWQDHXGW0obhYL\nQFy7\r\n=iNh4\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"387f8a788604692f1a7370cbcb722e038dc06480","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1628474496337_1628474546961_0.5749283255781286","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1628647347029":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1628647347029","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1628647347029","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f88a11d9995ee173ed295dd140f5f4adf9bd5e78","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1628647347029.tgz","fileCount":8,"integrity":"sha512-nw5dVcjtpJqpoNVsN4RXfG094OnD2RGlHGbdFLXF9rx5hZB/rnfcfn1PNkFpUSC8Gv+cGY/27xrg6hQig/ZmHA==","signatures":[{"sig":"MEUCIQCVzarNZwTFjKwzhvkoCUM1GUuiVMSG+PvVXXVvBXyppgIgf5sxWU9cjU3ete8Ni+zLtIEmGToSfNRnw1IS+w77ywQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhEy/wCRA9TVsSAnZWagAA9c0QAJDWUjKUKySx/Jc+p8IZ\nz3Jfjuv6AEewVxxPDfKA0FIWmkXL2S0ZjaiCF9fWYa64XeyRp5RR374Nv8qs\nFL0FHcRB6Mb5MhlR8b0kclHBc8VTpkt2hd8CvyATw94c+BMXcq0w0c65pTYg\nATWs0CZrKhAcS6yRHrm2y3GGu9earSwir/FdlR658IZQW+uZSZYcFJaAoJju\nXgBhrnXzwXAI1lLq/wC6ZCyxBqjbV7K2FKoMADtIojqUE8i8V8o4mNCM3t/S\njFOD+H2xWwFfVMGVk4TALm34M5nkUFsVgfULLBur2InaI9pYNPewJr8DzZr3\neAbSfzzaw/z3Ba3mwxuQU4SqdtfzcepNXjrEU539/lvHBvhVC2uyjxtNHqgu\nMqwuHAyVdlRExv0i2DTl6GD/fMto8aXj2Fs3Vv9Tguc+QIkuJK5R4BtGjf8l\n48clPy0srFhBAisJkuuvOvl3RBgZc7a5viSE4iMPM7Flc2Yl10RcnXT/mUwA\nWxg2WtX81BUosQUwH0VPd9QQGkI3gnRWVR5ftp/9d6dETONoS5dN5fxqr6jz\n1FMLFHhBcIefqmlsMNjcmgZyKM+a7PSqTLHq300iFq6hfNJDpwdzUWYTMdh4\n4Ec5XNuPEAaqoh+4A/D/vRCmX5clDnqfc+afSZ6bKIHgvwJ9wKvjRvg91IBS\nfKfn\r\n=RJMr\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2b5b3f88f0353d23c3cf111a1646cbb696f167ac","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1628647347029_1628647407887_0.1113923832085082","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1628647387318":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1628647387318","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1628647387318","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a5f55f4cb928c2040de579168d451bf3ac22ac64","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1628647387318.tgz","fileCount":8,"integrity":"sha512-CrqaTveyIw388mbQtvyUI4AG7DUe8LjMBujqA48PDD3VRp3Y1HSHUBLH2RYo3Ww1NGKixqTpW6uAHt4WmX1Qjw==","signatures":[{"sig":"MEQCIBs+TG/t9Odz+OAOVNE/W/c0Qr1udsFbuXbMe04+14MDAiA+4+4nLr8/vJYEtD7eE1kC9xI4PoHh3rx51H6JJR/8Bw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhEzAMCRA9TVsSAnZWagAAffYQAIdL9vsTra7Sv3RnBvLa\n3/4s8q0ufF/K7ITlxWrNsax5K74t4OKEVLgqEBbPm/G3QceLTCPw7O6rd7DY\n5e9HIsRZrhpj1a1Lxobvs8zaSG5UXlIE8jVx8IRpEHM4EIk2FewysUj+ibGf\nb+QVXSGZMFlm0u9F2WuWo5drdg9nBLSvXnpWPfzmUh14u5NfcjSNYRuAUQ7i\nkZY8D28Zu37bLky6FzeNCkLQBfy4bkRMHgq+jzF8pYhzNemfVZohOyEmThBv\nzV3Awz5ZyAiV3scGNdj+1WyA3e3wuxqUZgdBqupeLdW6WWUCung7YDOJIzRU\nt0wg5oyjU+zxkbq+71ybU0gmteyO945KgqBbUel3t97WyCxZQaVGlrHknt6v\n//QEd0/r7fLXrWf0D/B6SdaLK+KG968DkgX/wLIstSyEvgBLLC9E3/xPE8G/\n8Ur1bx07JutgZB3rH95ZSHv3+s+VbWWwyiYmLRwMR4006bNRZ9p7pwFacdKT\njATX/KSfAF+JmGzauCQr/MDBZmkYMJ5Jw0bnXSU/iIYxF6tIFExe+x0zpYtQ\nnnqVT3R2tt7SYOLsPtSPrWAczXdamVZRZBrWUGFcDKM+EV3fXHGjTGjLIPYJ\nv7Y7ktNdpeMg4SMWPex3Y1BqgxzW+buLPxhgPvTiySBQwvrTOdtc0kjwGn/y\nUGTb\r\n=xo94\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"96f7b00766b0751b617a529f494c83c89d7b98d8","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^27.0.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1628647387318_1628647436320_0.9573304866375711","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1628820112878":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1628820112878","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1628820112878","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"9362af5972c34e00d343440457b58002bc0248b4","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1628820112878.tgz","fileCount":8,"integrity":"sha512-iiojbxeUsmpFWNTv7uN07t73cbr/Tokq3L3YcXdBAGEJURwsFPO8zMsi1qc9wo/mGy2z9NJljzNA57AADdAErg==","signatures":[{"sig":"MEQCIAZZZBSb709PIPOjeEG1yVv6qtLx8rN+6k/ZhkAeS29WAiBBX78Ni+NdfuJOtcUDBK+yAjaGsAJ11WDk1gIs6DRzBg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhFdLACRA9TVsSAnZWagAA15IP/2e0aAUtdM9lb76UU6GX\npTQsOd88UZCjEacu7/HHwJ9AXqJkl7z5hkUq71qcy57/aTliLvhATXStXep0\nrI1c0/CbDC9kDRIDI3TZSo4ek9n9VsuqXarSdAi39zTCBrdSxnj7zHUimPfM\nAK9OP/QlLBTIN8WJJ0fSdGXpLzUuX7gRysDvyJkzK5N4aUun7/wrE0qej6PK\nBG3xoD7+KDz4/Q+qixfOwPGLKBqa0LCLFKmLMwXrAFU6kv8hr2jrI+qS3hgR\n5c1JyOnjLp4vDw4IxGoSK3K2ru1Y96RqEBpEeoDn/Pv1vx1eey0jEd4JOuBU\n0bYWBoQ3ITtPKtcm6DyJ7EgOLDxMk9vNcpG1ipxFiGgdIeaRj7MjipdPm1x6\n+hM1u7PzWHfB1w2KnvPqg01VsS4ZJIApBf0v3SOqPEfpmm5omHPjgIdbhBlc\n4k3FYbseQPTuXxy/DNsvSTSScBr734vkDOrbSqsjnNnb4ZnwYuJBNSPVgBEm\nJndMTlLXy2g/fAONkYIlxzyZxDujLIq0DOtksA8mMnnSvz/zJPhY1Sb5YxU8\nhR/kKwNhYqa6skKwKqzubVpS2BSZMVTbpR2L1ddX6bhgzMLE9Dm49Qh0b10/\nVtvLDH8vX/2NQQrvFxi+J472prmsjDqRvgAf24s9K7joOs4X7jsle6O4ukBn\nGGy/\r\n=lj6M\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"03ea5b6ac063fcd0f18e7efcd3bfdeb8096a8832","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^27.0.1","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1628820112878_1628820160497_0.5099669029322118","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1629424898426":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1629424898426","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1629424898426","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"887e9e21d40ae9813102a39a964d21c0c5f88fad","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1629424898426.tgz","fileCount":8,"integrity":"sha512-fBHX0If2VwNseXWViRRMZC3TUUR9CktOMcbbKqentFH72tGRdo8qXM5GiN1kZbXZhFJs6CyVyNBGEA/vGwVt+A==","signatures":[{"sig":"MEQCIFmCmwK9RVFEmtAz+UenaUN+VXat1K7jw2yIR8SW/eToAiBGo5vguGQtLuUKmfwUFXAdzdNFzoflp1/kQfWT6WYbPw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhHw1HCRA9TVsSAnZWagAAQPAP+wQB9C3Tn3VxVne1sWNN\nwJNfrVtkCZj+l6QXM2ZMdy7VekxpuEu2upu5DHNhyhg8LtDpwWuB3LsaAhPB\nG5ahRJxMsvRYI48hLXr4GPjOt8Tjkgbhf/OV23YpvbduKsO4nqI2qB/8A3NL\no0hi8HbJ+raglSurw8UofRe04lgsT26CNfV0ynMnrycW+lXmslQ7JNGhezla\n+xho7w7EF4i7IH+7ufhNGYFI+B/M2coPvWf1DmfNmj/5Bf+MmLLmNpAcez+n\nBFj0IIA2A/klWqXo2dwk88rmUmfBDjybryzgoi05bIs+kQhhOaIE1fCrbWE1\nF921voAs/VrP7R2SVW0bWABNUNL4vvKRU9LkxhofmAlx0WqAwO8UxAc0fXC9\n2eZ6YUGC+sihb5xyDZgD2BI98b6Ynu8OY8sE9PItgtqTA4s+fRrWpBvrfbSI\nwSzaadEWsEs7r+Rh2t7QA6vLJvQsqYiJZnyIz0/WfNm1X3LCurXW4b93mPgS\nY+mvaPNuykQQTw/mP2zN3IeU4fm2z1h8xqbZYSz1htsG1CZRfsaZzVGp+qWh\nY9t7gf5SXmKbN+2xr0gtGQ2fuaxmQ9KMd0IuioOntAQmy1UwSE+4NoJxhaJw\nDa64njdSeOSaLcf9p+X6DBHT3rREEZg6qRnHHAxoPjksLZGBUQ1cFmIjA9V9\nzlhW\r\n=JI7d\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"f4d72bb9c52e26f6871737ee70b7127a71ca0fb7","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1629424898426_1629424967407_0.7519837654159747","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1629770518609":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1629770518609","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1629770518609","maintainers":[{"name":"guillaumewuip","email":"clochard.guillaume@gmail.com"},{"name":"brajalu","email":"benoit.rajalu@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"cateland","email":"acateland@talend.com"},{"name":"pagury","email":"pagury@live.com"},{"name":"md4","email":"contact@martin-dequatremare.fr"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"miaxos","email":"an.griffon@gmail.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"},{"name":"tgenissel","email":"thomas.genissel@iadvize.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a946ccc4ecac7f22f4ee4a39873a4f47300b0de5","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1629770518609.tgz","fileCount":8,"integrity":"sha512-JdbU6WY8YFToHRlrKxVzjKuKoy2lM2y8phB0jbJQXw1kLeZwVNcFsuxerLQMoO6XDuMY9XFalGpK445PGDlKCQ==","signatures":[{"sig":"MEQCIG0pVOfQXjz4v4MNpDUGIsvMdzc3t0a3LrNS/C2IV2Z+AiAoq5PpBnypuiwWCp5hoPjZtrjp3PC68FG1y/78T5GYeg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJFNMCRA9TVsSAnZWagAAwmYP/A985GLBWUiYg4AuC5pi\nAbQjxLGVIKgbHn+xvXT47NOLpK/E2IGY5dLq9lRKtNylGyVTbt61IZmZwPLq\nOF0+uiUOcwDk0O6RlEqmMv6wnbcyvH8+xM3KM0bTGzGXwmuMRJZHwWXp7jyY\n2Nkf2eGTjpmF2BlJoSc4s4Vk+Wa2Zyb7y+pZGbiVLBLB1q0xiWYafoGjb2X9\nL9jkr9qEq7z85jnLDW2INO49XVINkUwQVTizShTI189fZtgZ+dMP3KD6JZq3\nfpOoKVs3JVML4GBR/usUR5x948FkWd3V65els9+m05ViY076XtETGqSYs9dA\nOgtl6wrOrTLOcIFmAblc9ZFLVIfC9IXJkVFwTg7KDkcJ+/jg9b9L9Bj9M4JD\nQ3RsywDBh8u1soYAtGH+XXMrnYJbkjQQqnU/xrM8uE/gtuGbSbm4gWRCaDho\nI6/b1lwLYyn1S31IUaDfO9hVoGJ310LZZk09POBDk1i9QtQZ3XWOwFocGu5i\nhI0Mnyan1civdvV2fQCpu+M0JInej1Ldu7r7NdYtj1OnNCLxKP4V+nFsgAss\nMKDxgcFygiX1fc2gowewkTMHkZEBb47FEechW4v0GH8zwM3XgZcRmdj7p3yR\ng8U2aegs8fTtDdN7CT+nmJGC2hktkOVzhaECAwYUS8jRBdVdRAm+238SSTAQ\nnx+c\r\n=vDv5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ee9612a1b7e52aace7f5bfdbe7fb6c0d61053994","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1629770518609_1629770572631_0.12437175881041806","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1630288984407":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1630288984407","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1630288984407","maintainers":[{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"994f0513eae47099007e1af0a7bc4f1e37c6381b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1630288984407.tgz","fileCount":8,"integrity":"sha512-Ri8dX301xMqGRPjFRhiewwpcfwLjgmB87OjPMgb0gfd/itmPJ08UQ6Y0fjmoSu0FwgoUfv0JsEPjT6gIvJ8y4A==","signatures":[{"sig":"MEYCIQDoDLPEvq8rApeIW/nOCdFislMcnS8YwCLssLVr2qS9iAIhAOMAKf5Ljznv12SLDz52aKq9884FDUrcpbal9zMowDLP","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhLDyQCRA9TVsSAnZWagAAL1YP/i6K3Ai3lHEzrnXV0AXu\nPKP/ubOUy9dieJTaGl8Qx1Y3vcL9mrqyvz8ekYyeUylvvpbHEn2Tyx44v6qd\n6J2OstO/8f+FfcSchkXzMcwqUK2EpxbN0av8QyJoC66G80eegtL/nt0JHA9+\nEvof4VOsFuxY7mqjE3gS4l/jITsvhvUavlmz/2F8ippZglVflSurXZ0/uXj0\nEPzuUy3rJsaVnmuQTyIGIQhpO2IyRWtdlGNLYpBT5P6G4Bax8/leSghxlqaT\n1gFFzNzl67wzj2XzoqAVWtM33nUvD80JFQmv5djy1KKNC+3pjdmQC1TmwNiP\nBDp5CIuCY2nQGA1vI8gJ3kDaf/6Icm7ZjdR1oS/+dzH/zOkpT+1xD9Ih0f7s\nJKYtqbFdgCXgkCYexn2o+PWzsvzhejp5CDYZ70vwKA58fwN95t80PefJY51V\nvLO2RbGXobvgvl4Slinhqsp4pSESRBQYSwjotxgqRgHKAhmPGkvBwjdSByX0\npsuhKGucamIQGRmn6H80/o0HdWk/VNUnQrKNNwHMlnuLn5WwxQjYWY5lmKoV\nlSItHXJ4u78QcqE339a8nVqEPzy0oz26EfLWb+5LgoZvG3KXEGOzld/C6Z8y\nMgRO4f3mLl/moVt1GHbJ3e3nsUcHJhgdnvnb6QGKq173147cEmK44lfbmUjd\niMa/\r\n=UDPX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"958097e5196a7cd2e4e2312d72dca2e09e691ccd","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1630288984407_1630289040415_0.9975586618618126","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1631498614639":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1631498614639","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1631498614639","maintainers":[{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f664120a9b55b2da912755f70b2705998095ffda","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1631498614639.tgz","fileCount":8,"integrity":"sha512-UAXf/8L+pDoxTmzGCTIxk/eO3HWWr84tN7qfBAhb5dI/YVIkhiFERy09tb6rEhUn131e0fWLbpqlvwHaMAQouA==","signatures":[{"sig":"MEYCIQD9zCZSpCmKml0mBnvf/czPKAHv9dLeeNqTIcwY7lfGHAIhANrMW8/QXVV33UOOla0o7oMHJUOirqOzOE15LP9SNaFe","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhPrG0CRA9TVsSAnZWagAAmEMQAJeExFjGlh3Vea/0vYl1\nc9AEKEDepFw0urP4K1vOpfmwErFrGwhbvv9LcM4Fs7O3G46Wjl0ELCcFmwHb\nAgtG294p7FF5NhjGbezpnXPCf1VCxwe4o0KAsLabPrM4vcSOIM19nuxj0ZCq\nikxMOMeiLiYxZgJ1tJH4mws+vM3YWALDdwkKjrsagUAaanxjn4zFoBdGZfzq\nDMzK8YAy3gFQov4Vu30y+6CmusNvNNUgfFlFn0fDY7A7hd87vXIsVCxaZypm\ncMavtt7ywOoMrvCdzT+rnj0e5KUfOxpAKyooLkr922k6OUL9a7QB53DHkU1w\nae578cu547xBVJVfzgOfdptL9DzJsY7r4oe6GDbAL9SS6lbbUvh+AEPWTPFO\nSNdBhPDjA2183FbGzj72glrxWJmMiqRBSkEigiMkbP6OMzFHJqjaJnPM7sAz\nE9nH2yaIpTJ4zt78wro/N5gwUyneqc/vtt4iKARs8OEDKIFYYCYqDN6CiXBP\nJitKrgVZ92nv4brWd00banNcuI5g2oUrsjFCy84OIHsKTTayBtSt1Sx4Tkqe\njhOallKVtg65242v5jIzn4e/kxQpLzalpHH982Ht/TpFgnS5ZecK4GH6Vfmh\n4MXwMEtg5w/jG8ckiJLL1NoO+GzzWuKcUeQhvKC0z25qCUiR6cgNbEgCh0Bd\nGxGx\r\n=KZLY\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"78f4c635a1a508f7480a7a26f777105c7f7fc8fb","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.3","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1631498614639_1631498676116_0.264708182268778","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1632103286904":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1632103286904","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1632103286904","maintainers":[{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"62c67e9c04c181b3612a06646b22a55e146e633f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1632103286904.tgz","fileCount":8,"integrity":"sha512-kz5pxfmbG4j/9AfI4bmlzmZMlCXctcSHJ9DxMSU5lpHAu7bjKsmGxNC6Seecnmt0j4QXx65+6O6Mtf8J73WJhQ==","signatures":[{"sig":"MEUCIQC8p9RNXDr0rmMoTbcy024k3njcvpe2UK4JoHpFZVaRdgIgeqLfy8b1txj2zWLOQWHJf4ItNqpyuCc5oCz9DtB+hv0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"d6c456e93ad0e2806241f232e4a294b9629e735b","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.4","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1632103286904_1632103371372_0.17572918062607967","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1632276096910":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1632276096910","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1632276096910","maintainers":[{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"925e53ccef849fc8fbd207bfd48f783b9d95f8e4","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1632276096910.tgz","fileCount":8,"integrity":"sha512-wzfhuNVHMXvOQ4+XX1WGra4dl+Ute1TRtD9pNRHl2JQxkk/diXJkpV+Vz3h+95vpqBNK8b7mwkGMX4eVmlv7yA==","signatures":[{"sig":"MEUCIQDamK8NKtdoHWk393qFbnl3cKlhWCYO2P+RhoLgVXkIOgIgSLtWsqe77Pcijfkgrwyc22fcNnsy2r11QVqDc4MNzl8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"7dbb193bbd2003f2e669af46112f2d4ce8a5177a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^27.0.2","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1632276096910_1632276158209_0.03551642173278191","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1632362499686":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1632362499686","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1632362499686","maintainers":[{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"69714de7d8fdf504d00264d0ca3747ac01b79baa","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1632362499686.tgz","fileCount":8,"integrity":"sha512-ThqYTTgI/UvM2utidSa3lo9QACLzxDni2PfvG49XiYmJmUUXejuWTZCeJ4e81EH6XXGC/q6Mpke8ODsfAdEBrA==","signatures":[{"sig":"MEUCIQDuHG3wfL0Ef0es2kDLKke5BmvJHM2N/0LLSJUJZTwUZwIgfhh+QekSLizyMS85SS7qP1BzitGpOBT1tcO/NfSWUqo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ba3293523185278798a181915683fcbb5fc4f67e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1632362499686_1632362549250_0.7627760078263033","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1633313001120":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1633313001120","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1633313001120","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"e6f1982ac4cac464bb1107d828a11c06cc57bacb","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1633313001120.tgz","fileCount":8,"integrity":"sha512-zBSS3riVE1+IUmwKa2fs0iJyOfiv+O6IgClAkGAjR5+pQb7Jpe0Cc3X2QKQ7KFiawiLgnpK3MBV8h3SwYTIjCQ==","signatures":[{"sig":"MEYCIQCmueIbFC6ryWNv+e8AXbf9Jhpk8IzuBgNF/AB+D41+HQIhAJOxyQV+DW8fx555RTL7PmEiqgiIm83eXvj5bbShOUcs","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"59dd40fdb54899aa1bc6386f3fa39abdfa8de741","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.5","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1633313001120_1633313056087_0.8592111221970578","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1633313028711":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1633313028711","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1633313028711","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"37451b1470245b2e181a3e78e8d8406eb9f0595c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1633313028711.tgz","fileCount":8,"integrity":"sha512-hb/FCcyqlF2ZPopsPEcstza0pjXwErcEHj43lJlyBjv+D/2uecNHUpzlDHoLnAHM/5n3lI6Xehl0+FXtUV0o5A==","signatures":[{"sig":"MEUCIQC737nE6of5v7pFDaGICgaoL4R1DGHNDkX61PfLeH3l6wIgaEMqGWzn3drEzHRS9SzIVlQ8dPyLgQByM/tF5+5cTM8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"40dc571feae67f889a91c975a3f18b01713a245a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1633313028711_1633313081886_0.2146075587787526","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1633313119645":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1633313119645","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1633313119645","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"34bdb696818c5ddb7ee3906890bbf2c544d2bc35","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1633313119645.tgz","fileCount":8,"integrity":"sha512-LdpJcpbhpLA31eKBEbNSJJAZl5XhEWPrmE2GNkwScjiol8C9nKc+BnFVmJzoNjxfxoWUr7oQ2qIbwmVyCxAxrQ==","signatures":[{"sig":"MEUCIGbOxuyfwIOZiQQPTeZ5/BiUkWjpYKzplCVae6ZMae7gAiEA/VBoQhUh/Ca8uQ3sQ1JsNKqRIOhBLbfp5TDm02wZevk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"825d0fdfc3ad9c39b4a5becde4969d5f7c9fd5be","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^21.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1633313119645_1633313176926_0.9551813951906127","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1633917878497":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1633917878497","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1633917878497","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8bdc2a7834dee1597ae558df870060e74ce094c1","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1633917878497.tgz","fileCount":8,"integrity":"sha512-fQ1wk3z6727m0UnCXAH6omm2es9/NWSiNgi3aLtRq2VRHqqPg1+oXpmrynUZcf0lZ3vX9iiKMoTH8X4SYlERgw==","signatures":[{"sig":"MEYCIQDbQc7qSim7ej/uQ7S3zOHYjjGFhX85mOCBkvqLa2yW+QIhAMcgrtSU+GHBKdPQMhYsThLdCgZh5BpTxmiz8+70z5tc","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"46ba3a2346a3bcea4e2837e28fd23a0451a804f5","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.0.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1633917878497_1633917932512_0.8036340899221905","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1634263346049":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1634263346049","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1634263346049","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ea54974813ce6813809f5af0d1953fd7f888a736","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1634263346049.tgz","fileCount":8,"integrity":"sha512-v8nHIR0oFCUqO6vXQUkGRMqyxnqqSAF9ozCT+vtXKC288P2NBoV8AYvtQmq0Vturti8rGqjMSMFDyFTUG/DYzA==","signatures":[{"sig":"MEYCIQCQVuBJswFfjuK0HUcivi9Q+9wMY4RSE7ZTvHoq1YI8ZgIhAKm0tbvIm9wfT6FxaLbyrOAF1ah4W24REs87AoxxbYSe","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"984a8c465ac913a4a919e60f099eab23441e7c34","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.0.1","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1634263346049_1634263423098_0.5198148770772133","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1634522556199":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1634522556199","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1634522556199","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7ba32daaadf3ed00527d87610a1e3cb819b14a31","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1634522556199.tgz","fileCount":8,"integrity":"sha512-TToz1/yqxIdgBs8vHSPECFrjFy3SSjBt5cmup/nPaOuLTKlgHoJ7G0XNlC9f6+3exDTlYcM7hHw2EitcdizaUw==","signatures":[{"sig":"MEQCICsITni9AH1V5CgOtPWGVVBx0PqTu4TEM7107LUeQN1AAiBRnPyXfuZs5spgaaOSbUY1WZxO595GDZ5jgj1j5tlCuQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"f2a469ba7a172a113df77dda2d05e76b8be1020e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.6","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1634522556199_1634522619292_0.6129270056297091","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1634695308650":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1634695308650","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1634695308650","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"2609e83c90e4c364597c8fc31f6b9623119b13f8","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1634695308650.tgz","fileCount":8,"integrity":"sha512-mPnrVs2URnd0lAPJdVgeQOsiNNvtGRlxG8QyNkMKVtQKH9EM3lqhL8T6Yj4nvCzkcxOpfAtPcoLblwAvda+q6A==","signatures":[{"sig":"MEQCIGQyFJJzQH7MI/IhmQabPKLPh9vNtM28XXT3neVxzVnSAiAf2Fj40jP5P5gkWTpTfdvDIFLLl5kSR6S4B6aYJ2leZQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"dbdb3819e2684466d8ce05ff6c941e0d7693d947","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^21.0.1","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1634695308650_1634695368170_0.2825715774868838","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1635127386846":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1635127386846","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1635127386846","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f7397650539e6e627499986192c3019d42611519","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1635127386846.tgz","fileCount":8,"integrity":"sha512-S5RdQ5aBP/AL5kCH6zo9DFCp5T0g1X8Xpz6E2mIY3h44qzPlsM7lhBloqWW3Q3gYrthwkUszg1ByNnMN+lOzPA==","signatures":[{"sig":"MEUCIQCT2jis02XcXyiyomOMQHGJHFdgCHHamqlh6vpsu+E/TAIgEnRx79RV5I+7Wd7rU/JR6fXuFn8EWUfv7IUC9cDdb+Q=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"885cd67b63f43d61a0ae1f32f6d1b7a52e9aaf07","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.1.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1635127386846_1635127447900_0.2716235351903069","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1635127408266":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1635127408266","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1635127408266","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7c2424c6387631c39a155da8f92ffaecaae9df96","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1635127408266.tgz","fileCount":8,"integrity":"sha512-ZI8cuSYiRz6kES8bkDy1GzFeCiNxbK8RIDz4QgSyQBL5A1gmzorKWbBpBxCjXLwZPMDDqEghNnu5Hwalbrd4Tw==","signatures":[{"sig":"MEUCIFJwjQJL2PtGZ8g8ZTydHKz1+m1bds3kPpp+0gwY9kyjAiEAui7wyP7qODKmB0rW81o+V7THHOg3lVcGJLeAWMAIUh4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0fd2588c96ccfc25bba0f9cef408d2d892cf54b1","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.7","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1635127408266_1635127465657_0.4003007792996083","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1635213770198":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1635213770198","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1635213770198","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"348c53fed7fd0869812a8b6e13b58b15c4a3e12d","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1635213770198.tgz","fileCount":8,"integrity":"sha512-W1LW13wpU8FAbsud3i1DM3W7y66aOy4o8sZzn704h9Ki5pfsu8ts+uMqdZPR6Xq611vatWYeWWUePBPyyf42kg==","signatures":[{"sig":"MEUCIQCJVKKabHrLiu5mvdyeiOwSyjbkBNnfKRoaeH0Ob2/oIAIgBe8aCYj8x4sBehvL2OhTh1aZPSXCTUFNvHVtfo4fqBY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"f372d59fba91a2b9ede161bd1905c418d53ff22c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1635213770198_1635213830639_0.7971152426456867","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1635818504628":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1635818504628","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1635818504628","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"bc2705f7892828c8bcacc748b838401c375142ee","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1635818504628.tgz","fileCount":8,"integrity":"sha512-i6qB8a2WQofMkg7y3EwxdYb5zRCF3HtgT+ivccMiaqYtYLzXvZMvYmQs2egvCt2Q8DN7BLhEyMKBl4BXISqXbA==","signatures":[{"sig":"MEQCIE5SvqsdRUPO/exLGBHyo6MYGXzvow10L9lGZoQcn1/EAiBr7VbTVVkPawurVL7OZcyZPF2YcxUacP7DdVFV3rqakA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"6d48bb9691fce60400d086859df1b2e9bfd32ca2","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1635818504628_1635818559075_0.21772641245664004","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1636337068092":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1636337068092","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1636337068092","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c4857268dda6b9785aba332731cf18318c3c19db","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1636337068092.tgz","fileCount":8,"integrity":"sha512-Gvg40VjHQxaZqZkSeXtyY7id9M/CMyONERsYJadpfMgku/yf3LV/8XOZrIawQGkG8sPhSTYJE8eQhyN3BeetJw==","signatures":[{"sig":"MEUCIQCXaJYrM6lBezr/y42z/uWRl16UxFgEEURqUKhkZVPvtQIgBIHm6XZP/qp4pWVh9ft2vQZ522wNwl6yi1IvM6CxhcA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9ca48864ddb2ed6781c1a4ecfe32d2e48fa29728","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.8","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1636337068092_1636337122328_0.6535754530565885","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1636337092870":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1636337092870","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1636337092870","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"dfccb5f54fc9766f8991e938faa1bbd7148d1d7f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1636337092870.tgz","fileCount":8,"integrity":"sha512-4yWekYWUxsXjR/Yw+CmWSxW9z31FpPS2OqkOyOqj7qgLWlslykfZLNrRuIJW33A6WKo0vWUWkJh3rt5uIgJWYg==","signatures":[{"sig":"MEYCIQD/ii0bwD6KtxzyALeD8Het/kUJSDZFfMuMgF1OHMJZaQIhAP6U9y9EFpHQ5huFpaOKXGDbZiG2ifgrUwzPURnvzZGY","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"856866acbcfb627ee5346ed1b9396c3cde4b0577","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.2.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1636337092870_1636337150260_0.20744633912155885","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1636941720315":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1636941720315","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1636941720315","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"5bf11111a55e5af4a4c23d64fa1385b302afee80","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1636941720315.tgz","fileCount":8,"integrity":"sha512-yk9QWiT4EVjrsPhnI95bRdoSIj/kdyIkq+rMUStwAs3MEElqBnNogRg5+WNhwhMSAl9O6uPM7P2vArMhJrQ4dw==","signatures":[{"sig":"MEUCIQDaq8GOVQo4UVqi5V8ji/04uvtk1WM/HWHXDSYEqMSrFgIgSRshnQzjj3unt7+lgAb4EViOxERcNfvNwh7Hot4Q68Y=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ed4855defe6cdd603e02fec74e132cae911b9e12","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1636941720315_1636941779144_0.8494367841233799","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1636941823473":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1636941823473","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1636941823473","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7e8f818b55f7a95c93fd78cd825e7cbf11929553","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1636941823473.tgz","fileCount":8,"integrity":"sha512-pfoQ3B2Rqk2ChS2aGrIN8LU17S9wxIE4XoXF+GjtLRlyrSTm8ux9olukRFQ+2FS2kWqZV6FjwZxnF91mo2E41w==","signatures":[{"sig":"MEQCIBOaXA89mmJxExWuJ36/UdnQFNCrrnHbJbXmfxwREeMSAiBE+V3VpNpYmbc1Zvs/sGYPAN0kgaPcjqvG3jmCqxW6kQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"c463745924032a802b1600d6526cef2f8fb0f566","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.9","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1636941823473_1636941879844_0.9875552388386639","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1637287404307":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1637287404307","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1637287404307","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"81426d5e123a035999c67ff8c79fcd9f35e988d6","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1637287404307.tgz","fileCount":8,"integrity":"sha512-+hW3KfTDWfDp1PdnAKp1YwcRCwW9MHsctITfH0PPml3hxAjHjHh2llL9UyzR5LiZcPnqhkrm63tie2grECB+Xw==","signatures":[{"sig":"MEUCIQCtjXL1eY3zCivUMO6tjXFarxHKH51+IYJECP+2jUaipgIgCoEFJ9OGEqRuRhRq6kdb5CpLoB1ySh6OD4OG2DxFxH0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhlwYlCRA9TVsSAnZWagAA9gUP/Aj5pJREq5BU6H7AFNmc\nVVtqo82h5rYW2iLp2hzmkoy9+Jb54LyBhiu8Jb4nRJjr1rTH/FTninzeoLbu\n0OLdZl0+wf8iIXlg62TItV1xJz30diY1FtJpJBoKCgs/+LuOPqEcLNAgxyHB\nNpMrC0gdBetF0B0Dx4aFdJ3XdGoCUb3DEINHFvfpv4oK+BzyELo1sz5xTngH\nTtav/nWNTXLcOwRNdHsmXUZOll6i2nN5x4eesb+GWLKXlitly4ERNbazreTq\nYRFgxy+GS0FmL2WMuw7oHlbV40OiqjLIOmR2sjPDjLjbK2PIruLx0ZqYrV0R\nw4va9QKZc1I5uV5ARRveIH5kKwYX42tj1qA/piGfEumVTZdAAcYWalwrG7ey\nZP9tRm+vMjGxAiWqNLg5ZOpVslH+/EHhfo0kOJwOGLRCx+ybUg64/uLL33XD\nSaLjo6/C2JPzPL7A21WdRHUkqRy1Dd6PP4abg9nKS4fYgpF5rtasusZP1VpF\n3w7NeN/0YcKFCL9lsiFIR2iaUQQi+GEDkhcBlJP5kOGklMyU5ix3CjNQxug7\nEvv4Vfi8pDHjveqj19Dnakm684Q0CGJWWiyBxSJxmv7LFHu9qV2JvNOHbNkM\nUfQHfE4DTU7JTKfqt6Zfc/NYIY+APIu5YO1STucCCs+8kek4cq8w/s4+sVvT\n48EX\r\n=nP+B\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2c69a9397d3d24b1410d1fdc4fd8e2ed6b3bf726","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^27.0.3","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1637287404307_1637287461194_0.17038864423561684","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1637546660946":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1637546660946","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1637546660946","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"21a77d1b36a32a7ef0b5f6b045486b830ece90ae","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1637546660946.tgz","fileCount":8,"integrity":"sha512-HKkokvLCz1oqOQnVQ8TloWmrHYlEeic42b6bDwm5EyDYdi7pcgxzJLdY7uWaSxF+PYcRxG5TxnBsqSuJV098Qg==","signatures":[{"sig":"MEQCICbVOweu6XqBz6c6caN9FC6VHHmboyzVK/8HVkfKoxavAiA3NodkuyUXXyYl2MbVQ+IkfzMKegNZgHTs2AN7ET5KxA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmvrdCRA9TVsSAnZWagAA1sgP/joUtz7Afhe4KTcWKnJg\nwK3YJRBI/zSgk0LgG3oQfnC1zoGGo6dnhaBQ2P+e9qS6fWL6xKTu9Qfg9Je7\nQ6wSkWZtDgmktNVjKGpukGYHZxmd5UfyjZpYUIoLFDQ5cpDG6eaXV8S7Syyn\nUQH+MmqzBfZntSlwh8KuMy7Yy9UyW/n5vpiTAkK3ylpUksQ5onQB0AZt0CQ+\noIK58l/ir8Tbp4wPgo92blxvJNYPvpnHQ7soNUUn5Lv26+cY6EAABH4ZvRDR\nmbyBPzUXsM/tvIofraJtHx7X6llxYxYws0b/DvnNJXM+nRQuZf3uTImB11/w\n8Xx+vkx9WrjDLNWqsXpBnzB+37w3HCzyCX8pikBwTo2r0FF9FJ+cPBbg+t5x\nwHktHpS0uqRNGWsuH4dF+YUeBw83prdx9SyXBZBFlt1B3rCVHHzh1LIDh9dv\n7nx+3CbdGVi/sH0FIXDN43xRFcN8ONf8ciIfkfBaW4fclHKsc/8RcDZQtWA1\nyRQ+JpJsArZHrD7zsgOeAVF60GUzMnMbzv5TpQR+VW1Nsvj4n3e+tRmeyurJ\nIqAiMAl+GPSoW988brGZWxfr6KJ3SxWH22DlxgNzEYLvSedfSIJG0Wa7Mavu\nOHaFbozoUM59C+deToTWRFjXm/r7uL+fPXgSBmC/8FvtRsXgdLigBsStKnki\nR7/f\r\n=KFV4\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"256d39fa433486f5073b8063c9ccbf9b91b0f6b0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.3.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1637546660946_1637546717664_0.8415368114716444","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1637632921253":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1637632921253","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1637632921253","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"5ba9da2c20af64fae0ddef0aa0f77359c76bb0b3","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1637632921253.tgz","fileCount":8,"integrity":"sha512-aIR2nMJ0SkIj2zJp3BqpQQq3b7hFaTnH1eFBTzqwNxkGra+DrSwQigHA4SlZqc4JdPAYCtCj0gHV4VHCuhCORQ==","signatures":[{"sig":"MEUCIHxWZGUu2VO39d/VtaCywSr/11y4LJuKkyB/EjYS+mGcAiEAzWgoSC+ng+7apM+kI9dVFybA4pcAiJjz9d480PPPFvc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnEvTCRA9TVsSAnZWagAA4GkQAJdgGm2Oiqbhd9jG0mND\nE+e4tzdAo7EN1/nN3ah4O73guretyPnjuwDbMr90k9/DhC4+sGGUraXQD4qh\nh9pxz2n5as2z2BYJnw4sKZeD8vcufqrXjNJovTYZdfmW9wBX2aqRsq6ZxYti\nlNz4BS6ZsCvPrRlhKOW3A92lhewb5iUSrsUZV7BQKwAzTz0oHXd5tr+riJfB\nXuMIGhFVuZIrWK9VId6uJwK4v/GjgMOXMdO5QHbbHixAXIAKluRsLWs/zWM3\nt7cQ5VZUoGpgR5lZL4Ea/p/yE8kOgUSBk7IHRrRUAMLJfTMNC8ggytRqA8Sp\nxF1LZxO2c+qJwk8nGtNNbNJJOj4EFkVuaFaXelWCkgKRC51paMAJcvlIyDAn\n2SH9eeXYMdN2Mz2vcsgUpNW6nHKIH12VMeODRcMlLyOSUX/jFSUlvnc6ZqHS\nDPyrbtKgYjz/zTjLM9B1/gEKCc9im7aeh/fgUR3q32FLkbiyhy5lF7hJgVEE\nisE2mrGE9nc7wuoSREnh65w+1IIxA2wmHeHv19IGPivRzBr15TXXZ0kt7VrS\ns6Q0yRf1ECsO4l6l/nY2r53brqPdAU+OYvkJ5KmUkQ2aVhi6wHocUDf+4aLe\nC4awUmjZ2c/6hwexZe8scANWYEQ4iLFkb75gdBWYQqmdSmIo9mlOIp7g9tAC\nw8o8\r\n=7LBN\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bfcdd92328424e3eb4724368b1d767bc77e3bd33","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1637632921253_1637632979267_0.11533264011454514","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1637805733845":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1637805733845","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1637805733845","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"4cc7a20c1e0dbe05e32d7de88d8a3d5c14c41c23","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1637805733845.tgz","fileCount":8,"integrity":"sha512-n23elmlm9T3oIt2z+YK3WdBYLYKsR7UL58tcTYrnWdYsFpFdhV+tcK5jlHWwlTsOEtSP0sSgsQQgT9H/2f9g+g==","signatures":[{"sig":"MEQCIFTTKoQEGylEDpXaNDMoKUHy1WfIveI5P1f86b/l2wjxAiByOzqXBWVskcS797Or8gylZLmlGuIuWvVPnOmtjgqBMQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnu7XCRA9TVsSAnZWagAAl3UP/0CL4OkmO1ktTr8MQACE\n3tMo+GQq15EkSNYttKy3tJBF1DzR24FMayUnltjLXDL2g+qRUYfibZuefkGG\nMW6r4SpBN7aVsJRDZ3MiHPSuHbj92hd2RVDb33lAYuH1KmXa65uH7v4fOls3\nU1JsVASWLnn8r4GNbzfWHuKym3pOCfaaeVkhpRE9/bJex2vMlytPwsArnP4p\nk4P6gYjE0/v8J71JyhwI12QmjVff/ht3J0ekBpFBI0zDRQ15MlhOiYBVr80l\nZW4PCRvfCyyzHOjkYSq7M6HsD9lPGm8ODrDu25F7DcIFy2hYscDXMxL8KaTV\n8UqmjvQEw4TtXNSRPVaPyA2k+S7kKhxm7ttg9V47DNdKBVH7tiZeqgfCw1iE\na4YFQn6WpNu/gXqpuhD9azJprwiUWRLtZrcLXSNVDdtl2+MCzFbqkw/VNDKq\n7OGXh9iOdu4uE1sVW39BHRmlpNN37okidlwCZfxleExcw8iJDTZ56h+2fUhX\nhqlql5Iilffrl+XW+Ow5p4NtERzPoWDYJPHetG1zWrmL4iwHRc6WUV8pZoLf\nah19gxm50s3qIImMkfblRPlF89po+0CnDvNyQuL5RfovRZ88RfsF+cXzA+ky\nDaH+j9BQQzZQix1i0YFlez01495KOeQ1xoUX3bEm8puVlxo7wtITTi1fZ2i6\nl6M9\r\n=jXCL\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ea69644884e3c416517bd8cca72ccd2ea2714fa4","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.10","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1637805733845_1637805783603_0.08144887867614092","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1638324127149":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1638324127149","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1638324127149","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7459dd3cbbefeda53405cfa8b1aab3797f2ff8be","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1638324127149.tgz","fileCount":8,"integrity":"sha512-uAXcQTMO7kTth69JceSpNjiFlfQLtUKWN1cea3+FK+5bV1Y40bxoP9/4ZKDbr+KstPp+SBjGRioqXNT9EVmocw==","signatures":[{"sig":"MEQCIEGqx6+xVRM4yBivBhUyByIMD8TRKr2GZ0ORALwMVfoeAiBqt7Zfz+s3ZRbrfafsgFLbsiNTEsi2EF+EOaRRp6wO8w==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhptfLCRA9TVsSAnZWagAAl6AP/0vYwBSt/LCsscc6tKak\naOD7o0REUNrrpFSll5tx26o9wFmAQlDnYdrcWbX2yyZMyiS5LU+twxHAkjSC\nMfU+aiDB8KOeGcSm1ubgq/8nMOAbQtNi6FJDnKM+IDrN4Her7EM9Gqd1s7ZT\n+2nujgrD/LBCEq/53b/PBZRjOE9c303RUpl+pUuKVw+8zEC6yMFg75MXHjCz\n1YYQHEIegsXCgrCyWBpVGn/PSU8V7T/9Y7puCOgRzlTSWmiIqLYCiJ//QfdC\neHTZJuONh22sEHZ0mml2Oo9+qAxDv4dYFnovqryoXUENCrhCVcx779rntuHe\nwHCfdvMg7PVJVlCratFXoY+96sGatpbnnuMmaJOWz60Fn0cBEUJGyBmmbF5D\nsf/kVa4fC2y1xKxgSnRLW51pfLa/VtCiAeaOid7gqN/+dLaWstCXxj9+eRMB\nrfCIhKV1p259sZJQ/NkTz9A88vZjnLvICshsJldXKVA8+8OCHwGjpPZGTc4+\nNivlH8blU4Qr0HN2+0KyJtrv+dLFFkY0Qraib0C9yMA+DXE/WtTHgSt0N+aO\nyjQVAcGUbvboLeBXqGLcwQAHXymjXR5+hxcd/nXJ3YsCTe9mgNIV75q03aA1\nQFwhtLgeMTwDvJeNonZHfVh9SD0o8mF6C3aZHtIlMSBP5rezXHi2Q9wHtLCV\n+tMz\r\n=wjqM\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"6c3cbee18d0538ecb5313d94b10cb674504ac591","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1638324127149_1638324171678_0.36263938152444286","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1638756223599":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1638756223599","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1638756223599","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"e29c51ca9e8adde00fd51abd8cb6f6d4dc5c14bc","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1638756223599.tgz","fileCount":8,"integrity":"sha512-tNzWFjPVcQRot+R2y+g9YkYuC8gom+lmdq55jXLzAZQrzyJSxUi0LqAxE2KwDoeifzOkg8MKqAEEBy3ZpwsUtA==","signatures":[{"sig":"MEUCIFF2/ABgIuMdZ3G256l5tGSi5N3dDy9UeiwXeiNX4ok0AiEA/xdStaPSfGvD5jeXQ1gy0Fo4UHrUV2R3ED3ri3iYhe0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhrW+3CRA9TVsSAnZWagAAizEP+gOkLl3m4MRx/bwL8HI4\n97Izq5RfESs3rYLov9gFYF2v7DI81q5L11C/JbIHGQ36p9egFgzc0b8msG28\nqYkyVRw6m6kTapeA9+d+hn7im3PjBeQ4ozISZA7So4brFBzBOb/JqsjEF3ls\nfWiDxk8GOvrR0m52k7srq4kYoXx0wyM8EHgLh4d+yNZ7VYkKIONa/VSEeMGt\nr0d3tJLdtzx3b6mIAHqOKEOslbFtgnSp0+ghIMgfHIyF5p1p/4v55tjtlHNV\n0qnCEPtxaRXtiE8SGcNsYY46d0zVL42YPy+5/N0dy/f7KhEI7tIrXcEllp4e\ngRcTMMvb//xS622O+gEzMQ3X8S/+DZ5PzvRAXPXYfRZIp7HnQmcFCEClr6yj\nZ6iTuee5MqPzhAE+vmvfaWAhU/zEY14oJQz/7ULKmXUWsU9wzOtC/S4Br4yH\nY9Fmo4mYtXN+KiCGVxzFEBO7efoYP34IXnc4Cuxqgt8EhE8Bb4483mZk+Xmq\nOQzSLFK1mOIS8PokX6lqRg10hRFVdkA7lwLlI3DNw5tqK5bAUaTrQdU5ewrp\nAKdO7yPSfuJ7vw++7isXw6R64th0qldErov8RKX8hi+BmYY0pdI93IN6bZcQ\n2QMw+eAd/P3wUmEjKR98khaScUCBZ1RPZJJKUc8acJj1EWyPJA/F3atfmrai\nW1cQ\r\n=rXGN\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9a0427e4f294642d51a031fb87e16c8a6cd6df7d","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.4.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1638756223599_1638756279284_0.6552997291192908","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1638842580192":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1638842580192","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1638842580192","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"91c257e633d229ef83188f0eb37cfab1af6a8eef","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1638842580192.tgz","fileCount":8,"integrity":"sha512-/IG/1nfMCD3TUf9A22p77dTw4mS0HsfgEwf5Pqhrp2GG1JAejcwc349Ya3JaRubsgDR4GexQo5b3q82fM44FnQ==","signatures":[{"sig":"MEUCIQCjpv8wzikjWp0AiYiP03fsPMA2WA4TYwycRnp8m7LIrgIgU2Kjt7hH6sToBxKM5OM/fIL0qteq3LQcjpND5So3To8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhrsECCRA9TVsSAnZWagAAGnEP/3gaLX11rDkMvRvOoMKs\n5tMmmBjNq70C4abjzwf/EDq+O//g1SWXvleIa8PurLOa/K+PkoaTmLMZvBhZ\nGDjNGcJnxb1LC24dJjig0zngYq9sAT8Vpz82mmz7TcUpTqw3vUlqxpySHAZ5\nPk3+D4XcN5BYYwRpY1GwcFSG/3AaIrpEyxe1Y9hacCRj7VK7UoKI1nvwzN1n\nOr1Ryv/bB8NRC+c3b58/EEgMu/nWRn1V36dL6STXSlcdGFmF1UtMQQAJO7U5\ngaDXCuLA0YGhdZsp5jEKd8Ko/duU3LvM36ZEKt63XQJeb3ysA4JkRUjV0rxR\nE+RW5nJgCiHMlfb7lmf0fAGmOG1+Fxw4if+1GOIySMhtTHX9OJUg/+MYWZw9\nn2WhUrKQ/CSs80Mv2dmC1rA2xI09Re+teDXDDUm1+XahBYqeApCvq3zBpkeN\nwcqdaF3WXY94pT16L9fgvXon0HDKmk4DdWdLcDPVjoZcS91lsopQT/2EQ8eW\nDwuBhXkn04H0tF3/YsD/ictbie+bqpRHYQP3ImvSNLrLCU7moaX2twyiB0BD\npURCvkRqOiN80/WVZUH/xcK1JUVOn7xSkqdyQAJ/QZDsofhjYWI/g8Nci7LD\nsABClsM3nRa2bCPriGFaARn48n79yT+sxmIYw9s8DczpnX11mXrB2YH9kGYg\n+7Aq\r\n=/PSj\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b067d29fd8a3b6698e1da2240f2e51fac1514173","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.4.1","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1638842580192_1638842626455_0.8115263612073984","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1639101765011":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1639101765011","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1639101765011","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b9a939050cf0823942a6913d93f656c8de912052","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1639101765011.tgz","fileCount":8,"integrity":"sha512-aqmmYug+YPdp6tgcvkNrDOmF7g+/yMtCpsvcyiiOOzOVvuVw1Zg5YBCUgqko+Xlfts0YzVO2EKbV0yKnIFEHjQ==","signatures":[{"sig":"MEUCIQCKsTwBSzxNcc/GyPdFWqK/QXavp8mZlcVTgesE/2ETdgIgeT+kcy62mt3+BIeSayIJ3UyprSu6SX1OUSmC779Gk+I=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhsrV0CRA9TVsSAnZWagAAq0YP/23Gxh4vBXTojx50BAa7\nnMZpcCftxsPGDuGan6YHk6Dl1PDMX6OE3P8CQ33ZVf6+ozkCVemFr5hyQqUp\nGnV9hpCu8XS9pmkYIKLuER74dzdMRembyNInQJm/p8vPMeeJLh9qCwuEOxG8\nLQ1hg5JgFCBHe1BL7+VH6e9tN/Hxn7QBCa+KcgUHlqM4CQCmiCfGzUdhHksJ\njbYPO0m2y9hyLNrLGK6qRCWM2F9k4ZMhU1l/QVSaUyLKWSHQ1e41TPIf8yGk\nssw1cU+3N/G7JEo2lIeRzouZ3xX5JrOgbx/fnQHcIu3QnN0EE/XRmx7ULT6p\nROAOPirg8rerlwsbpdxMeGKZFLVvrCqH0dlo5hkUCTYKCRr0EQvAFxL3zKcy\nyRvWZZ/4nTpgLwGATryTA9aAWON2a3Mkq4Zo+ghXm4cmA0fcZ1rWoOqMkwkP\nsg3QQ2TlG2YrIxL+scQlA+odrrQWZcvpMR2jQ2Wv9yMCOoAD2IeU2GjcRyK6\nmk7CH/eKA2bY6DHhIBJHEHS+9LkzuzDN/NdYQp9UgBGL5IFzwen84R47RapL\npPhHsrCmB804MhqvKJy3hlZUrdhQvaWSAPV+tifW8inLNgCcr1qKuQbHrWPb\nEKk1NlePUSI62QGQRBt8R+tVs5zECR4JhHjjbid2qrmh7r3CCGF4Ev6XYYBf\nPf39\r\n=dM4e\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4f9d21057dc05b8a7ffe98b4592ee02845c79162","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1639101765011_1639101812510_0.020012662092677047","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1639361013854":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1639361013854","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1639361013854","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"31d8101085200c520ec1fb0ea5574636b684797e","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1639361013854.tgz","fileCount":8,"integrity":"sha512-VgsshKvrbRCNAbEdimjRw4XobST0jGvn8+in6MdxXSpDuKwS9IlmNLDEU0NYEaZYFleH5Zk3uwmjcJ5WkJFuhQ==","signatures":[{"sig":"MEUCIQDtjjEbdrI6NvM0YuskOMiK3M5HfebY991e9PZwX1exGQIgUqbn0CLBwy/Xy9lvJU6OXpxyYmnk175RE2kV13gXPUA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhtqopCRA9TVsSAnZWagAAv4AP/isSd4xQjwYgAsvaqDrX\nzjF2/3xteqwMPPQCvtkvoknEVzL4wsjVT7oWZWw+RsVUS120wT+DzSGiFCzx\nI6uJxAmgBy01eIHtYYPgc6NbRRvZpkBlNkthzXGaivu4y8S4yqJamg5yfDGI\nWwvScyFASyoMq66PQhv0JowkrmipoD5SCLY18QJSwQI2kjlO783O0xBVUR1E\n959ICYoloD8/1sy1rv36rEexwbXWKTVur5RWNjyszTgUbwXjdtkGexjoYmiR\nQE/xrZbltKTfQK3mOutow9nVOMPsQCveJm8F4l1oItuHYDH5s3AG5SdmZApt\nfhn5PhfvKfH7VlZvGe72AeglCQLJyMtb2+m0ofzBJvFDAYfCBQeXqpfFd8+L\nBVYnTkW9Zk3/naxS6g1150jjad23+PC2klptykmLxWxHmCB4VCoUPigCkz6k\ngEEneGAEmVVoVeHNg7OZpAqmqlFebvCbRf6p7yD1dpipb4usoqO/1sgY6Inp\n5+A0z7LvXpVhGdZGv63iguDhBxep5r/+AOEccJsZNrKKzZ/o7fjGmMWoiaAD\nWWtZY0yV2iDrijMV9J3RrRm//dChqoCEG5/tSQhAYnjFnk7uRfw2hihfgwKR\nn/yJhvKy57LOM0JS3A6MxG5zPIfTyHJ1t1o1mDoT+mTMStUnNiZ3gIh4E6hg\nWo+b\r\n=Hg6w\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8d523e587584b279492c82a6a64c6922336d941c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1639361013854_1639361065151_0.3168759869322566","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1639965834905":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1639965834905","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1639965834905","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c5eaa7edd0b50eca3008a1521a9628f647e9512f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1639965834905.tgz","fileCount":8,"integrity":"sha512-CEMxKuqMeWaDLY9m/4do2uUKrNOhxs+8rte/9zFVkgYYjV3ycqbX6wOx61mTdYdncs7E4yPelo8kWCIHWimRhg==","signatures":[{"sig":"MEUCIH7psLmFXiuKQQa2eFh8atqXSUR4obQ1vmcq8YidHW2OAiEAsP0yLAkbWHxRkePt3PGl5jDRDZq1k4p9JB7XUl+r/HM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhv+S9CRA9TVsSAnZWagAA0+cP/AoE/iW/O4qBUSV16TtR\nkgo8XvKR6IqcdqyVjq9dkUmvM97AxVIzzeZqQs7rNfCedhAt6N4SfAZXBJRu\naybhohEuttHk4aI6oPeWgIkV9OpKRUV7r6lWtnfUK4wl1xkESfsLRRJN1HJW\negCXTbq6927LUewz09Pdc4oZoUEsmHst/zHnBcT7kjIP8IJr5/lIb9XpCX0R\n63evB0vOfzjcbuHM8EI/p3fr9Jun0PPObA+/XjndAT1y31S1e9c0tOKobrdK\nr7LtJb5uYF0x2ySoZWgn9PFXjGnK4JDCZ20p75YYWBBKWZgP64iwF+Uxin3Y\ntRF+BL2+0BgVYaLif1ZZsYXibDtgQVb6seRZZqz2p5LifawLkdpUvGpo/nyt\nnuCdRtqc9fB0tBcseUY23MINW/BgG2y9QsYVEWkZpiLDSKYwAhji+qKhDAUi\n/SqzlTnSijtfJLmoUshJupTNZPA8k/wL27lqpE5uz1jLG6c1KYeh4hk4soUf\ni1LpOXS5Ng5xN/nV+1S9QnZl9JhJLL+Dxh+BFV0WpfPQ+tG0u2dJquHlpPYu\n3ZW0nj6lSWYjTAmdNZAYLAWf6eJUGmKodrMLCmwjhos6SdrOcDt8u+9mCBG6\nVJKVla78atsH3a86nc5gJQkzxx3yDPl+uDx2uhZgXX4n/LCrTeFypUesxopX\n+fwN\r\n=iO4Y\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"f146ab2bf045010f044a6fa12c770ed595be1edc","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.5.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1639965834905_1639965885439_0.5797541893618348","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1640570599778":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1640570599778","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1640570599778","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"140ddcbca2d9d436d32a335e8a9ddd254e011c93","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1640570599778.tgz","fileCount":8,"integrity":"sha512-Neic4CmyfjMCJgI3IFhtEVtcSQq9KKIUufhwSU8QJyMy/ru7eHs5gF+NFqLS0m83wh5uGJyMx8HMWQNGOU6/lw==","signatures":[{"sig":"MEQCIGkiO3wjihqWNufdPSiyfn5q9x2VZnYMPXcAuOwadcy+AiB6PpRXtUaT/6WzRYq30TTBPSaFH9lUhicc3SBbMKkuqQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhyR+NCRA9TVsSAnZWagAAGUsP/1CBY2k9Y9UcuNurnUjP\nN+o7urRxHg/rKsDuRYniUlwL2gHSjpu+kn+Uze6oL6CIEQYQ15fu7BeB/nE8\ny8yG5FjuMDXuc4TV83fcRnWR1kFgQgacgfHI/XYkAe3Rxe26GvjzsbKVQH8D\n96xrzDtGW8NkuyeHmwbwoMZc0Mb8k8iaH1LO7hmgM2Dyzme834ab6T+2Roqa\n9HeWMHDj4mctlsyZOBjqG37PNwTziM0ECX05BCUkDmeBq4S1DfaOfkzVYtTc\nb0aRol/uGvm3pbsv4zDBsym6X87nDuRBYYfQ4YnGmVyDT+gLHYZSH+dtmGSk\nCH0TCL1vUpegLkDE2W9c245bW7QMxmCYtTOczGOTz+N4mZQoSCG6QPjns0KP\nXCc/ZtF/mpYxrJ1moNWcsWlsMFo7ONvWE67dXcPKrkMxYllrTIrOo2j/5HkW\n72X5O3bV8PAvZ8HkXyTvrbrkCJEcNomJ5bl3Vo+q9eMYq+Xez3FCUgWcVW/y\nGQhhpbZ1/dQ3SYWgFxiI6nkSpw5W8OI4RUjCpq81pPvNv3UNwG37osjczfQW\ngduUktggX8w+ZdWlp4++1PLej0q7kyfFt7NJDizbetTsgp7qV/Y2XNa9m4xr\nc5mN/TMNJu/nwRmHiZ8uYnuUN8eyzHfBEiwGy3xJ//HJplTD1i5ZOWKHLVU2\niqKq\r\n=/5BC\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"da4e5771e19c74e047aa6cd9886e0f946fc004c8","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1640570599778_1640570764887_0.09156802822770804","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1640916188050":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1640916188050","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1640916188050","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"4a2b63bd99276f914463bcdf3c34a7616c7c31bc","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1640916188050.tgz","fileCount":8,"integrity":"sha512-5pA/jJwiBAfuwS55AK6Iayvx1llzfTxlyJ/flSDx6igC3m7qXNd7KhdtKXF0dN6GmGRaxyNHAr59X9T0eebS2w==","signatures":[{"sig":"MEQCIBlnMGYHuRlQIpkEuJF9WIwsBqBFq+wQt5F5u0vle0wKAiB/d5MLs6oI0K6/nSs2Cm6KNzswNcQgIdKUrwj5MiBN6A==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhzmUTCRA9TVsSAnZWagAAg6oP/jgQtBwvI/k6ZpynGXja\nb3zJyIIzw0L4ALezLUbel+wPoz4GRTDdisC/bDYULuxtAuxB/Vpzs0GugsPO\nxKbigXtoM806Xq8o45PhjamI85MLcafJFhyKnAeSbFS/AP65onnimHCrrmqt\nfmX1S7kk0KpFWS3xU9nRagZarpSC6cHYjroVg6iCh58Bk7aa2aMPtXTR4k38\nfdylXPrdVLex4jAzdHIXX9m58qnfwQyfFUs93yaQls7tdPKhG0ISf7cEihoY\nZseUNiqCEzi4Nax8kSK4LfI+RQnZFt+cFx9XvmfsJRu5FtlWCjiIPtS4rGlD\nYHjlkPa6Dk1+JzQoSc9bLRV5ZHoT6uloRSsci+tcEApalL3h10LXgyOrqe4p\nafVN79gnCDvhHtrAA6GCi7/cBRPknxWGo7FJ8ULIjwqRKcZxu1lwAJBdQHu+\n7Kkg8hPkI9/+UL+1kSVQoPOtOe1+SO5uLcCcVE33NMLlgtfZt86EVZ16ucqV\nfBqmyMAeXqfLyDupf0wzNKUOUX5QYLoEJfaH4NZNW3IL8dBDcXfgc6K1XMQh\nYfMWS1Zgo8tkNxntYMUnC07SZBRvBeBulzam2Q9x2+dSeg7Jg2OKiamkmTDW\nzRaBPHy9nY5pBg6FJ5f7mYLRjSSLeMNyzQicq4ugfkhRQryHR7Rns76dm+JG\nMpnJ\r\n=PL4j\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"81dc58b4ec74aaa968479a4a5832db4e44547035","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^27.4.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1640916188050_1640916243206_0.24592093685562144","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1641175490579":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1641175490579","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1641175490579","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"85de047d063d3472557a58d077f1ae09d9c0cfba","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1641175490579.tgz","fileCount":8,"integrity":"sha512-NNqcm2D1hr7K9Tq5DInTf7xAwGQZJIIzqLnxwbZ4cCYjLvrqX+v7Z/ZgqPMVqRf67QV9wqxaESEjkK6ZAsKomA==","signatures":[{"sig":"MEUCIQClqVVSISjR3nkb/WPC9mUgWp8kahrZLlZAqNQyJI6PjAIgGVxxjmnnW+gh5cAIxResEj+21WtCGnpl5ACs7sLltu4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh0ln2CRA9TVsSAnZWagAAnKYP/i6vQ1Ry8OPwZEKOADtP\np/KIqt64pbKwSpEFg52tKI7IoxySfBU6TicKhu4JM6ogCisu6t7TMzLzkubP\nKus3Qchu23mkhLwH+hF+agrds1jbUl8PugFLoM3YK5MReZZEYa9Nwdj/h9tW\nvju63BQt0SFHqU1T+qTsLzq1MnkBSfM9QCVjimccMY9D/njNWAjD9sTkZaTZ\ndBSNCCZzkCrBoX8UffVxqA44goUpehv1+5F2Hp7z091IYeRvvVVQR/uKkyJY\njIs4ZvwKWXttbz8fvlPs70bi7UHXrrBC+Z69RXsxqXTgtsiYXgZswcvsHF7Q\nRFrXR8/f5+qvl6pDVyp/FHT5hrSSf4aWLcDVUrCcyYaERkxRLZIFnK/1Vg93\nQVUzUUxvLJahDebLMQpmw/KCRHJeYQ4jBqJsZjLQU3CW7tz+l4iZCLn9kzop\nRZ30RzRFI44SuPHmVghpidvp5h0HERQVtmvHlqOSoRcQq3C4HIzfkajcCdkx\n/fQ6lJwZYj4vbZQVZWSZ/mfO/sxfw6s0LOUre2RRoZVkP+P1UBZVuRkvECUX\nZC3ziuIo43izID4n2mZrpHJiTFHqDY/cX+/P5M4FCoPuIpcFw22v2nkcsGL6\nyGd/d9636VU9HgrKQQF8QzNOluzs1fr99dvu4pm7uybe6TtPZffkMozxk5uP\nBejG\r\n=aRkb\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"a7aa85039b10e8e6556f337f0e0e6acbb3031a0c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.6.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1641175490579_1641175541905_0.6015107151871137","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1641348124460":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1641348124460","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1641348124460","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ac2df6a1527f88f39b91c3272e246a0e9aa1e234","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1641348124460.tgz","fileCount":8,"integrity":"sha512-wyxMrJ9Bre9zsIiTcmzyxcFRvJn22VPpZkM3qSLTgqSfNGexqa4ETdCouNvhMK7yKP1FoPrDV3Q3e1nWpTl5Cg==","signatures":[{"sig":"MEUCIQC+0yBKRaR+pBH4ODhqTYTb6Opg3fryjU5+o6NiuBU8rgIgdJkPq+ZixrYRbXWn6z/keNl3Ch/kn9A5mqAH7eBHFME=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh1PxOCRA9TVsSAnZWagAAM3MP/iLZqzFXzOche9/3Ggky\nv7WajQakSB0mtSFhfdtKsSUDeZ3BOyXHmKzDmaSOcYw5dIJorktvvSEQXSEY\noBV4Z8j0NN6j8UO3Rwo9sT9ELyM38CblyiMcavX5cqOO+vR95ar5prL4LEYg\nT2BXtsmQo5/nofBrTQiNsWfWbzqf2uttHDw6lfNKVCOPoYU0DgFQJ6QwiM6k\ny6WNe/hPn2fVlDcGXZbbD/CCZps7O1sijYHoMRhVrST9Z5lZZIFYQPPuW+Kj\ndFfBtnaTNdkX86MXXj02y85Q5o0OhibVLBH5TiFFgXrR79mk6ZVwKGxCHe3i\njtND1wrEJQwN8AExysh+xkECGIPn7jd+uOTfzoH9pyvb7ZMTwewxDdoQFhxk\n7rXXnxBofFPiqxUa558ndpkUmtL+c5Cj2ltm2LPkrXaYKN6eucibRqxqzFHI\npAMc8Vi45JJzev/h2vbm2Fur4n8W0mvJkIkmTxC0+WlT8SiPO/zfbnyH7YAs\nH+6qkbFtKD3jejpHOkyUDlDADGcJk94gmaYNmUBByYmmFBTr4Y5rvj53O4xw\nRl/Ef5ucl+YlM8nMncZL7exDDyFodF5gU6BWR+93Zhy2IRsTY36cjKc339f2\n0bGOeAwYGA6q0mLMAis8Bu6WaHB62nq3WudQg72Yf7GWqD43VowwUMJ/mUA6\nPeUX\r\n=ASO3\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"008c650fc0b843074d95942f65bfda09369e0f21","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1641348124460_1641348174422_0.9460627852458279","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1642385059185":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1642385059185","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1642385059185","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"516f1128d59cc6a3b3dc0286342288116f508341","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1642385059185.tgz","fileCount":8,"integrity":"sha512-K5h12+q26bZFEhNBrQp2mTjr8iEvzjiWpySI/H+wV7AD+L4zucxC+6kxc0t8CvOzg9tHUXB6x8JBb/wWHmZ6Yw==","signatures":[{"sig":"MEYCIQDj8zKxEPFBFf/tp8qA8MhWy5EbWNvs5GFuC/6YmPWm/QIhAMkOORKVcYsGHusdXMHptJQKHLkw4Fgiq0B+aX2glkFL","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh5M7PCRA9TVsSAnZWagAAcR0P/RVt4V+qLcqlaQHpAppD\neLAFjywW0v6X6z34e1qK6eXLKOE4QELmOBJWgiho8PZzc7go0gMGdSG1lB77\nLKcC6PFD0is+zFvu+Hp3MWO1sdVi/y2QRYitin9lW0f+dyEPogtfE7k0mf0D\na+cRVQqDe/c+tTjregDpmjbiCH7b0eAEsMoJDO29KmfUEgdggb0D7p/ynAkU\nISxShc6fwrXhmQS+avze0i+1HO5RBlFLiiK8I4oM/yod4+gK6Dgfe77Jd4CY\nTsIUf6ACoLnXvoBLisVmRvv4/sSa63srVbX7vGpBzsfZl0IxqOQlB2Th/jYl\nfRou92k82/nSvJb12cUjP6+j1kmKwwOVggQYSEr80G81tKGDNoQYdYXXvfDA\nCqOa/8OQ+WpJ/ExvW2JrpYiYgHaVuc2M4N5kvntxZSwfvR05+7D11NNHdwRd\n4eEaoftVCUxc3ciYeteTfLuOZZcWm7Q3+GcGUKEDuobg9Vd9VtXWmKkGW1PT\n72v0kCJUy7UYuC2VWxeVTWjCbMTan7EFTP9aL9LTBhm0+UwPTDtqjY5N4We9\nXyj9hDtBk3S4nN/Ax7q95zMDaUvMQ2h60fd+A7Cg1FGcY9wcsKh9K+HZVrjk\niOHzUiB32FFP7ufOqUn7kptmQKfb9Qpl4usUcjXs6S+nWsuGaxUuh1vUraAn\ngTUf\r\n=bCXz\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ec231e702eb542044ea5f3a652e09ecff8b7c5a6","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1642385059185_1642385102906_0.8310768616280451","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1642385085432":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1642385085432","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1642385085432","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b1ea4dd24e3470ac5907e2e9deb54fa951d46d7e","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1642385085432.tgz","fileCount":8,"integrity":"sha512-6ZkVjrun/TgLw5Fg7A+x4gKHlP0ij8iHyuYZAvnhOkmEZmSlOOzi2OC8Pi52Olk3QIzTnAu+Fv3/GXqf/Hh63w==","signatures":[{"sig":"MEQCIGC0dU96ziaKZjQ/6CThToRyfgie0vjby3qg8SbXdlpMAiB0Uadym0asJyq93Um7Rzb7m/CbgbB2nGdhgP+w8XSOSw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh5M7tCRA9TVsSAnZWagAAje4P/0uI6i2Ou1p7295GWaH8\nRbkNWMqPjXdiKEG0KaVG8ycWb0Ux9Ez4MlFXGiQRq88/AP4hoGMgqd2F1Q3t\nFFZzIdGMPtdBr5rWETA43m8PKNbDdh6w6Ts6OJSB01Cfy6Dq6zhRmViCTXyB\n3OGPM4aafw7ysnZ33AqoK0GZSjVTCRgKqc/vh7VRZPTdxMvRVRJDM54wP1QT\nfiwZ5hpXn+ATE+oR4c7g5vwFuvbBJWSRbi0h8VkmKRBusihkCL5BBj2QD0Kb\nWpapKPxc25fg8YH+H9ECrC7jzdK5H9s0deChg+um6H7a2l2IxuxngaZTMAkB\ndkHzsYdPdxaVN9uoc17DEXDYmjkAC458cPkjsO//UxmwxevB5n3XfzzTTqzD\neIDLeEeSfat+vmz02Ost/7ZtfCsC2Hy/QfREDp6XVWNeoTe1/TFKKUGdIB/W\nHU7fZlynCItzUefbvUu4f9bZyzBYPzC11X82/n9AzpSgMODK/mErKr7ayvT9\nHQPo5MrxbAdT9sFIRIL0EjV2Ib2l/PAzV0fIWoF32AAyzPgU/qut72KtV2OK\nGIDQ+GLbpM3ApNmSn7DIv+kudgpSpCY2qcyNo/SnIwn1DR043Z21xOynn2NS\nlwsyotmSVBc0zES95Sm3UHr11c/nZs5O1bB9yUudhy4C/XwgexdR9tYp57Wd\naplU\r\n=0mpF\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9f5e804897b46ac8bb7ba5e3366e737675aa0337","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.7.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1642385085432_1642385133635_0.6483004501669523","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1642557710679":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1642557710679","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1642557710679","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"26bb9b7dcaf6b9d33900ee6fed9e948867378aa4","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1642557710679.tgz","fileCount":8,"integrity":"sha512-4kMax51NRzuSIlOJ6kTUf4UOyMALJZfiDye3xlw/oiakkWL3g4v8lF3x6V09iOC774kTp5QdID0fy8+MjAUSpQ==","signatures":[{"sig":"MEQCIFgbCw2vJM6c3Dcx9O3ld13NvvisFldctVbd4RrE4/LcAiA+V4kB/ymDbfLWyXC0zGYuhGPC0LqWQdpw6ouP4fLl4g==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh53E7CRA9TVsSAnZWagAAAc4P/jWLT52433mCcayTakgf\nfByZOYVJXE1kSDE7Xhvg6OhUubb1X72E4tS3ND/qopxOWNYgBFattMTTx8p/\n9kbV50xEreWPuMXwJ3eMDH1d1bvrrO7kr4DQkeSHjXXluhGwKdQH7nxtndm3\nbW08sgdm37gNicY79i0ut+Uw3AxVKL2IDCV4vMjTPAiqSq91Sohat/fxE//l\nqilWd7/lIq5/IP6FvJuwh/DUs4tPc1AZdg3IkyY2IlBGMfOSeQWyBB94Gdst\nudx9QeO6Tfx9nss9pNSrlQmMnLIIijg1bj/aDlGhKwoTHmhQs99xiJJqs8kO\n/FWa8PEuzpRopUkOuukrDu65hi6mqltSShYiD35/mPdFeBOcsX0AIEppACnc\nxeEplFAOffrnmSWXXnRDrGUn028eLfq+Chf5uJeDfpTsUKxv/hf2iftTrnNP\nsoliMqqLlzSAY9ZvADv5qfDQYjr8VeRSLDvx3fREg+q47yd6kSK0Ce3u7zfi\nFO29QszvUj/105h1kKO5WWAzPi8WchMDx6jf6nbDUwGbaaeO3O8N1LU1X4zG\n4SzLvqLH6skOQZ2adYNH9pjvRSjbrKDQINKVDXGdJBe6OJoypmROnR+gjkhM\nsRVsb6Zlx+pbt1+u5fidlzt9WU72F0VYqXvv3oN09QAqLGhwuuCUJ/cifVrx\nSKF5\r\n=Jxws\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2a800575a9eb19d1c29388edaa278b14aa28528c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.11","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1642557710679_1642557755631_0.1837194458325988","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1642989708617":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1642989708617","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1642989708617","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8778c31d0fac6f58d2014130d46726b30c5cbab3","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1642989708617.tgz","fileCount":8,"integrity":"sha512-vbPJXDH5oj1W6sBxkKPD4f+lI/YAsaB+jn5PM6zDo4xedUwKSpmG/Tn4AnJucxc8m//nusXzpeu1Xj872xUPEQ==","signatures":[{"sig":"MEUCIBYL153s1hE62fBfS7YZ0N/IxIxg1k77p51h6CQcf73zAiEA1Yz484imwqsMN7U/DvuyUxizPzKGjt/oeZu5Y4KTEuE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh7gi5CRA9TVsSAnZWagAAnFMP/3pb26QHzKJeNcmEmu/2\n5arV7K03EbfuDzmewqybhNHZISJ/DIzo9Tt7/qIwFSmMu+0NiSbJoM6QLgdo\njTB9ca1VLepXIYQVQfiNGnltoZc2GLh8bAiNUxdEWtruQy1OPzkXUe/yxKH+\n57OEzov0L7KBi0mVTmHkUAhJTLPC/4D4guaROfKX3ZLGhW6FvAZBI0mlSHcz\nMQWffm4rus392KSxrJijAkUM3M0v2nbZebAZb7S37WMHalf4NJ+WdAFNscdt\n1ltQwefZAtDojs9oTaxWLTjWtnTXvPeRimfrW2JM8ScRCfRoZOSxCxsPXS+V\nfDfOLexVo3oPIUS7NBrMHxfm/00gwY0SB+PbsQwTwoOM7yl1kDyOu1ID5LjH\nu0xE8bat3AEZppNmLPltS93LUCSJljSFpX8BiUWmKiylYz8zCSYzXncLNiza\n+GULY0Jrbugr2CWp8FaNyMOEQDx0puFPgb/R9rCysvEDt8f4+pc/KSazHauc\nSmEeh64Gd6TmR0Nq2ckyFaiGX5SQ2Gf2OMKie7HBeIZRYrCtUjkGqMxO6G8G\nS8aeOExrIaX4pMDbr4u1P5rjUnnv78D9XkyTl8PKBX9MHimAV6oOc3AnOLw3\nwN3raBt5lGwbOqp+VF+TfK63UNhz2MrbCOOLVtSLu9sq9SkmqdV+boff4eJG\nZvbP\r\n=ym7P\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"811e5dd62ce0fb9a2ac866102e06f5ce4561dc14","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1642989708617_1642989753827_0.7860517510909384","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1643162527885":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1643162527885","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1643162527885","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"de8afaa35b28a62f8187314192e3022636dfd129","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1643162527885.tgz","fileCount":8,"integrity":"sha512-ffAeUfgBFcRi/WeHWHDgpPUcd5HGkvzVhCMiWpDHfrKC/Ev0p3LvN3SrMM60RnOZmi+pRmd7oYf435aTA66Pfw==","signatures":[{"sig":"MEYCIQCPafV3KfU+4caYDu1dNOeafWIe2qswoljfWsNfnyaQRwIhAJEpQEYD9IUPoJK3XYn0AptOUkItG6a331pvhWiC4BeX","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh8KvMCRA9TVsSAnZWagAAklEP/jnYMbnS14U7iQKxepKG\n9g5mdGmNeAA9WnJXJq+tPchwmRkHUPzlOW4EFGIpgmmLyH492pHn1z8DiR85\n99tg8DKqcHrnVVQ1idl5/CuryHRt063Ldq0SH2CTIVHnh3KUZRodeZc7liWg\nLwf5pC5evXH/gRh2LdX18lah/zy7HIHzzloFIBbX4sHrfsW8DU9RpzgK9iZw\nPieHtqXN6qR1Xdk5BBrQjR62V56/hB2Q5X7JT/jxp/DXC0MU/QlW/PkXwFwk\nn+ooM3foSEFSFhbpqeMnM4aU5+ywcMFJTdHdOlbRq9vvSabW29NNIWOiU4ZS\n/ZzIvEhGtdvl0r61IxehMpEumdmxt2pkHLRdldh5pSxkRbBcCSR3v1Tm1guL\nj/OYbJK7Z6xNBtvwRgfdGqH4+R0aKHb9V6Z17wu+fk4iOQFoApjCURfMCCmG\nxFWxdTuzsCsW7nG8TRXsMMEsQIQgsj4AQAWftGwOzACSwfnWITv5wrbChDBr\nQoFoyO60e4kyOUyq6Ve/3nSrYXp1VFRGB8t7e8osNUTZDreXB2BhJXV10A0C\nGLuzgvxB/isO6C42wNG+pE8HqB7ugOMHzFnuCgGQQThjyAUk96P8LvbFdI9a\nWm64gtx7O5nyut0+TN5+mNTYTx7xcIA8VgAxH16UOHm06aLpcPgHZEKRY9hz\nPU9W\r\n=RHBU\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"259f70ab4092c02b732893808a1a9e111d96bf74","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1643162527885_1643162572529_0.42372705316141923","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1643594633123":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1643594633123","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1643594633123","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"4621b228a7c6e562a1946b71738fd43483fc3fae","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1643594633123.tgz","fileCount":8,"integrity":"sha512-/VCVRwaTLR/dRABaST/jlTHZvq0R2PPU6hMVCBslJRnS6ky2jIBMh7dZLanzcshK0QmX23PzXW0dz+SpGvFCRg==","signatures":[{"sig":"MEUCIB+fvEeJeDTXBCM5RcTsP3QrKwvNKKmrCo8VychH8AucAiEAqKfDO4BbtB14G+JKkSjBSKVIHpOjIMW6GNWCle37BXA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh90O7CRA9TVsSAnZWagAAyqYP/RFiTFxE1EG+3Fy5HGc7\npbdDaHjBtEA34zZjNdNKDqHfQWhdES2aT8Okxwj2v1FaSkpM62F3Yufw+Y6x\nQvSxuIII1En0L1WUpUoYah1nl2xRSeDxpnZuE2k20obWEh9s1YdYOnPF/H7A\nzTehFnxpVKfjxiCmTvF+DV3iviJb56LqXTVzKaDMzzHlvvdlfE7KKGFAj6Xr\n2A8P0FCHEUQMPT63UklmdJCy0ao6dmHgvtGlZ9VeNCFJZWxgyROTGgmOPOvA\nNpTP2G8UKGy2YU55YntcwlE7fNq2FbnRUv450f2O1JDoHOXdlolQZySaCqId\nbVJelmWUXSPyDzTsPKjGwY5Z3rwru/xEgVrohOGgk9tUqkkxOUNbX6N/zjIR\nQMYceV7iEPtJB+e35tJDGtwI32MZkq9dZzGGK7nN2fqNrLtxi1Yc5VqSicPH\nmNvx3eXKOIcyIrqD/JiVirc9z3jbeDYdhyS8JYCVg3paQJAyFPtCX1o3vglA\nZ9U61umuJLIKE7WmlWmH+TVd4HSB7xmnTmq44DN4cwUDIEpKZThZ/hyTdcV/\nX0eDNbjQegSOIbLWMND61Jddc1jVEnuqn7lFTU1Gp0v/vuhNi/QJzfQR77M7\nMqd2PDldfI0/dhgioYmSJ4fuw8UDWXj1lAPTxPpafIiPFpQoPPQcTx/4reLs\nOQef\r\n=qRZ1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"d3574b1849aef31f8cb0fe65837cd8e4499ace26","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.8.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1643594633123_1643594683104_0.6744732656903099","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1643853809186":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1643853809186","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1643853809186","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a711bb1cc46cb684014e7b7e5c5abdf2b3ade384","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1643853809186.tgz","fileCount":8,"integrity":"sha512-8w5Yc3QwoqWHbpEtFpjvsuz8CznVkAK0ZAkGRTT4/qykhsqZsha6zco9WdjXafbktDbhlWHB9KSooaORS+cZEA==","signatures":[{"sig":"MEUCIQDD3nKXAwc2LeXl78TUSU1ZY7vPGsROkEk13tmNeKe6uAIgY01qq2I+S7HnKN+MkG9MVjy9+aotx/EYEvWT7y73HHk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh+zgeCRA9TVsSAnZWagAA7YcQAItCPYQ/e16w3JNXTfRQ\nDp9nLHcpETDbiTvV1DbA0/m+o24HfmhBQs3QHYpSm81nA5hsQFPir5gpnEzy\nv66jRod5J6QFRdY1QGlyWr6hES2/CwXHplw2a3yidOcXJTQRkC0UX9sP8aR9\ncQiQmb9/bVlBs7u6p1AO1Uc6NO2yQAWLiDkbJPxf+fLHCDAHARjvLMhlvh19\n85vLzT4MfpFMWaMh9z/9wLpLrg0IcEI0tYuz7rIY7XP6T9TjYSDqJJeLMWIa\nGHzThKxkegbJTMIein5ZVzcZO6s7lO0I0vwuV7pLPGGweAICizv2lvWLDV1+\ntwkSpYLyHATGpy6O46iEfe/NKkHXn+qXmZ46jysVdP0QKvEsD7je/FDq6jPN\n9TeE474Dimdnx5chTr6WkmqhaPghyMgqT3pBTZj/AUP34Q6QyIqfI5Pww8j6\nPIfPRjhHT2PPG8mmgnWBZTVBpztDsySo/HuldIh8b8Lv4auCO2cRwNf8K90L\n3eJ1ZlvM9V0oTPB1NLSwnVPsoEttR2Vo+m2QDtvmWhINmukVwTUp4AydicAn\nhOL4nC3WHY8qGulmK3z1pJEgcV7wYAgfNR6k9Cc6axQVEr5Ya9h9P4eGh7bL\noJWxCRuVNjNPUREqd2OAcmmTwaqAqqpIgnyCV/MGIqPZL1X4q7KmWy65HUaM\nAD6+\r\n=by0+\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ca7b859a3b20a651ebca92fbf57c9a086751911d","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1643853809186_1643853854120_0.9874554982766544","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1644285846227":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1644285846227","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1644285846227","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"055b26b441945c9c2932ad854565d5716c506cbf","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1644285846227.tgz","fileCount":8,"integrity":"sha512-p+F/e80Ek5MHHhAf0iH5iLHZtIbyunmpd5iqJqYIXVcN8dL9pFRCSQ/I54erTXOG6E8ztwjII/0ka9e5RCRhww==","signatures":[{"sig":"MEQCIEN2H3zCLv3GgNe0SHtb1oqt2XRSUM3DyI4gPCHTktFGAiB4IKZXHh47l4Zu8OSZ9gxSyoKK3p64J+eZry6LH+XhyA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJiAc/ECRA9TVsSAnZWagAAOz4QAJZB1akVOafnTd5ZxQc8\nzMrU7vXXFH1uThJd38Ki66hp3NLCSWkBR6RdjDsbnQAZrzMzqtCxETIgOiV8\ns+UG+QDuf1ByiUWTjDBbCxh8z8I9Oex/aySlU9faxZ1Lolx8buUsB1KwPXW5\ncUlbbtKw+d/zbxbRKWbd8rKMIxwVTpZySkpXsIhemvbi3wQ9DXdF9hEd5w1q\nzveyJeGmlmytpa7HsmYIw/cRWNzXPdGbRS2KFcR1kUYv90uV6E9CQ8r1z7/O\nnpXQvYxHTnfkfDYEHe0m7W33I8929xwefiNb0c9NjoTlisFY4UuQAOEVfz3i\ngFCX6J+SmE2VQkQW4tv3oc7iENScGlmkERPqxMsyDUOT5Yo4jxdXiToHHb4r\nqVh3FmORxOBqsKSP3NsgZoaDG5L/lR1c9c6uSAP2fvNpHYW8IjXsvkRzypGd\nu45jIxW23mgd/IfRi1zrAm8CGt1cmzLv5qG+xM9oTrBHBaRB8dtHiDa4ly54\nfY0kW9WEYTbCGEN68y2WtjlyLbPLrMHVfY9VEAnu6h3V8C7JCpGiAiC8KBHq\nnpdq41Glw9+3IPAC+9ks6ZdJIJWF7rj1lzNjXAgOSzb+x9MRHrweTRqewV+u\nGFgiZ6AMtnGzFpU1KdQhUZJ1wEH8jNlII4GRooLhmBYCOVgxCrGXjk9mwLwV\nTugV\r\n=oeC5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"1c0ed6804cb67db8a4619943058f3aa00ca6d34a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1644285846227_1644285892224_0.5871869786195474","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1644545319066":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1644545319066","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1644545319066","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"cbc76dbb20d283f298d83ae0ea4cedae7b053764","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1644545319066.tgz","fileCount":8,"integrity":"sha512-eV9+k6fuurdcrd0ub12/GFKJssYTpVdBzW3TlzCRwyIq7eWFuHw/vskdHCNioe6MnT3LyztxJCess84Ec6BguQ==","signatures":[{"sig":"MEQCIHesx3uj0YqKHgDfjEB+oyBDh0AUAsxOTE0+1W+FVgeiAiB7MNa6GssXsSnym4HjE7Qnk689+jyZlQ+JHJ9x3t0JEA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJiBcVXCRA9TVsSAnZWagAA43EP/3JtvNyKknoja6ql5MIV\nbve3v8O24GgI8FY7i2bSB5EiSQqiM9Qq0Rx8oHLdvGbNY773MHS2s3EA9tl1\n8YDcq1dBa2I3gn+b1B4LI9XD9nErCH+/Z9WQUnlic2Bl9FZKsDew/o1Tkdda\nYm86HEtPa+By3Hx44xswzSsRkLI0+dvqx0juJBqwbWHM2znZUXh23knNTw7H\nxRAAVtFso7VT4iiz+7YQh4g+3/fZoVQHGxNJ60itfKuoadgqc0UUEc4Mfk9Y\nuZmJpXZe6VwWabCjvWef+xryWd0Aj1QxGz2h/m1qfLPsO5S1x/mq35cSUCAp\nwBojPteB8aYYGj7XVTi+CQnkHZY7LGcs2Xs378z+4/5+kN7k0qF426zZc7aR\nuBUR1poIU9bpKJG0+eKFSiUiHWCMyaFL+iSwdGNZ0vgOabEzJXOZfGT0AMXw\njH6VRHOlcPucXxusiWnGze1iF/OTHQpy3/nbPOk6GwYfB57OB9PtNZpwNaGC\n9VF7EJsg5l+SaNRnjywgsMhlLjpS4yWEbCJKF1FY6hFp/Ym3xzf1/88EaKrF\n0rmvr1BV+Pa5nJnUhZqKBahB4PxlguJ15SzNcyRml1SQFxoWN6RAAoMipGgJ\nECaXzk5LS00ybQS0EpF5QTBGSzq7W9ROyl8w2X5cbbIyip6tAUlkeu5FtcKp\nXT1q\r\n=Y873\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"5462fab4914d53401ef929c7d0103f370c6f1ddf","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1644545319066_1644545366795_0.22793581441660948","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1644804191958":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1644804191958","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1644804191958","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8bcf3fba5c83655d9d618f7c3f9e804a03880d6c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1644804191958.tgz","fileCount":8,"integrity":"sha512-yk8SKMkiV+4nZf/z+vO6aojIlMA1NW/BUKEVcQa8aJhefHdkMgl2ag62rY/FlZgPY7lZV1X8EAZufO/BGfQqbg==","signatures":[{"sig":"MEUCIEgHJ0jVWgO1N3ogkhwjptQu5Q11iQBrH9ldVHKVssQjAiEAzEqu8EBPadbwecnKQQ06onCyVKL4Jy5g1nrp8Wc0eEw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJiCbiQCRA9TVsSAnZWagAAMScP/Rp0iMCFuAuAbBVIr2a2\ndJPgzHFfoIR1r//WkGEn5L8I8qqpgPn7LP6wN4a/O1l6cX+hZ7huk+r03OB6\n4fgQSfoZ6/NQ+TACXUgH8MXf74CLSds7FqrXTpca9h1S03M5ZxE1Ks2vmlbh\ng6fWEBC3gQora1Ssx6QkLqaNM+nmKO//0U7cZKhN15XTj6jx3URAPo9GQ+zV\nF+qYItIUZ1iPDPZS5DLMdtpSkbx+Wo6NnWC5QJLnXD1+FM1Ymy3QqTupnO7E\n1G6jNJQwmwZgl+HkfGW4bbS3hEw/3zY+TQ+alc1IKiwnD0qL625zYym4Dwos\nkNWyQYaJT4U7JzGYUyPRKhjuq+Vepa8GkcBo+79nT/S0vQ2wDaAH2H1nx+WL\nzNpgAzKdWoQ7Or3FPwTC0urtOBGN6r5quRhc2WdJmvLvvTP9jFK+9bO5zvgo\nMuBPyoJLskSVeRCjr5SmW2k0VwpBRrnfDVMjU6NrW1e09vB3fNlTvBNe42K4\njXUHpXsJVoIFxR1176qtyHRNpnZMnTy2ktnsF61RpcVW64NTBFq0bM2tngI2\nET3b9u/Vy8yGInmPFaRu2/3bRER7sZ6nYW6rcrMIOg4jUS4RrnbVqk5BpLM4\nri2vP5phEnzrjgQxYiwww7MH+I0WtTgpbFeX/8QKCoZ8jl/EXsS2Dy7YcXUQ\nmMKr\r\n=VSq9\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"580433004272b4ceda69df89c63f68eaefac4264","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.9.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1644804191958_1644804240660_0.8437711218116779","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1645408911424":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1645408911424","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1645408911424","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1a2f987d8a9710dad565e69d94ea4a4595c12345","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1645408911424.tgz","fileCount":8,"integrity":"sha512-AKXH/3pO8c3Mqm2jtSC0aUP9yMo/XZ+E+q5/FJOnRIn9fuetbZ/6U75uJAgBfrjfymFGduvzng/vfsd162qS1Q==","signatures":[{"sig":"MEYCIQDHMLOqfNrBfeVo3/mWN+280mhtTuYPbV6clRIH9+OKfgIhAJX3JAYmszUQ+KjkGtogsqjs6jJ3tpD7xANkYXKmbtJO","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiEvLHACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrynRAAobDTYG94ia9hb0iI9+JOE6b2aliXwHReN8B0IXRsZJJRgsJg\r\nWAwSfwOTVISm7QkbLh/D3RnHP818pMeSaoVF8EY+Lxbqp39QpfDQT4PiM9EO\r\nvNuEyUSuKJcEYR/76ox0Vh77+DQLOypFUqziIM44fqBLxjxnyx/pVljPz4Uk\r\nYz3LTpCoJ6pfSUp8LIvZnnKCSD66hERX2PaJQQYZAIKw0pcUftblJSL1Tx08\r\n93DgCXhZcqw5y9f+tLa1GWFvqxAtCCWQ5ebZUsFNpI62mTNLNy6Ja3YXcK2L\r\nt9vMiGXWccfXozW7aYZRxIoPZ2J0GOKaM3uq8NBLLWcWcDtYIt1WPGpUqmWE\r\nXbo9ZW1BOH58De4qStrZfxCPk9/kqP8zq9ClVyO12yNhEDwF3VwdU6AK2gg9\r\nbJEVsjd7gFSj3m+foFlo0uthvl0x+ZsG3CTQzBRCDIZq459NNwsB+AKjaHLd\r\nmWm3Iwl/m1nJKvvcQgoRBX+nOlsc0MUaJuO23s1dQDLt2SM7Rq1/Nd5oWTA+\r\n/E42RoNQ5jG3m4u6A/np1z+sHIn0UHxUeJ34KMp0lrHkulz63+cHQBxk6T7a\r\nDSQAfSEKSfNM//yE/S85igOYrXLmZV/MLORIfvdv4oGCn/HTvp5FA5WpQV40\r\nz7+Kkt9d0QRKBE+/lxC2ZSZyFD4NuIfoB3M=\r\n=dpiz\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"7880718f96748a3f3649076d053fd40210306fcc","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1645408911424_1645408967275_0.5157708195845381","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1645409051123":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1645409051123","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1645409051123","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"6534a6f724c2ae0da1d029408110340ba8752c25","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1645409051123.tgz","fileCount":8,"integrity":"sha512-EE5OyZefFXjky3SSIG6qDlR8kXGL/dRweqM5qSkcvl+BNAVty916MRRty3PsNuXG61PhZnMp3StXsY4tX8z6BA==","signatures":[{"sig":"MEUCICRMW1LLq4URdEDaNwB9uQ8nzKKEgR/lAefdcLPC+HEvAiEA43WRvMCVHeL0xBxdLkkHPRVMtHEXSmjW9AKCO+gZtMc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiEvNbACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpVgRAAjVRyZiJxXfHX8TSQpqk7yZHIKtg8+KL9KXNDpUKlj0QytzrL\r\n8Zvkr+MS12FEVU0tlFQDZy/ROz2evxiItVE4BHDpf/nO7NLJ+q6z5PTfZwyF\r\nm0MRvFVrjXR55qSY1ewNItGu3L1amrQd9tMewdY1grQvy45XOxOVmsNwGUb+\r\n3oueAb7qRoOetXg734sAguku3kSYU5/sr2S+gWkG65MtdWCztUdM4CW4smpy\r\nA2OufxrXKpWJV9VFNCZNPpRYHfqCqPYLUErrIyClm1w931KGXyjZkLpKcVxJ\r\nsp+w8617qjhN2xufymP94ABCFSzj/xeVuflcjkbYIcc4sbC9c1ei9/F7gYW1\r\ncKbBTPLN5DE4YE6bnPPtIuHIPU7rR4QDi0pXpqxyG8E8pODD/tF+NOx7REv7\r\nGn0ROdMBHFZkfaUk1I2bVTmwTwHGL97VZx9m6f+/9cWmkar0tWytV6FgOVZV\r\nuetMwoSptY42RPyq/NKD/nuBSS4KMks1x6gBckT8/JSBIlKZVgeowF49O8pt\r\nEYghxC0A3HC1fRgCW/k5xDslY3210Kds9gS5KNgmcBat0r25iltcU85SNTvL\r\npvSAOZN1MNTNe2a/U0xoozHURuEgwYjtn8rb4fqCgPJwxSXKYrPFeDPAn24e\r\nB2wcPCH9loBlhscYjxQ34jXQim/NJkAUWbg=\r\n=EYfj\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"a6cb84d067564a9d09536a0302f0135c3ae959bb","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.12","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1645409051123_1645409115793_0.14772726199910657","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1645581802668":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1645581802668","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1645581802668","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"36086241dd8020ff86695050cba885e5d282d8da","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1645581802668.tgz","fileCount":8,"integrity":"sha512-O6T5z3xeZCWs9m04OxgVBi89eU4c/vAAdwvs/MuDgqktUcAPR172ZTFyeSZXeRh71HJRYG5P7L4XWxzyqQ4Qyw==","signatures":[{"sig":"MEYCIQDejqbJWAYlGN9fbZdfPFRKDoQp9ac6cq/xWAfbjOrFggIhAKQOq32yglkQydlfGMwLQbLUdtYJI4LKg0b/Ctap1tkd","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiFZYcACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr9bw/7BfnkS6bY+xiwfm7prJmdRlTF6jBnncb5M6Cfblio0omSFxg8\r\nIa2nTlt6lbU9jy0rQQPC60beRChO4AxLxXUArRHRHwNe14Y3hciIfHOWAPgv\r\nYTS4jwW0Xq+NK/ZVM8VOzbU8aayH5Ty2P+MC5yXrcQHZFv3BvcOIfHRlhAka\r\ncfGEaEdv/fGeu7agkoXqaYSbeSqql0lei/sG3I+A+8OQSdjaz58PEY52oTJ3\r\no3MfBMj8Z44SfeBp6UfQWmj3mUABbdlbzdQaedzxT8UfQzTtbX66SVNQpLUM\r\nl9XoER3UsUoDV2f3VDZJbgohtS6JuaH1qOR8/wsY0tCYFWDDNMP4OBe1e1Gx\r\nEmuLwMrEVHOr0/JzHS99Mwhhtp0/G9gfmJrAm1LNzxLd34A2fWdCcM03/id0\r\nAIeWcBUgAv+GwCK7VD2N5apvB/jiu1MTiWOhp0RHKptGioLnzjwM8ZOnlG5n\r\nuPL63iUTc9VmO8r/OEip65lG9CsWQJ4wnLeG+9Je1ZbYG6UWuNVfyPPrbwAg\r\nHyiXAeIAXhOfVu3OTcfx3kloAbXmjWxvjNM7ltdLMZDdiJeAk8HKNjiBDD+1\r\nv0XlUJrZP0AwyA3EAK4yGGq7VV43LQWSNPE7V6WewCowsTbOk9N2mFdrPb3z\r\nXp4WuB9T5r6aJgX7pCbg3lqno7fdf0tYfWc=\r\n=Kb5b\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"e1cede848efd0bb36126c96252bf6878ff62c3ab","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1645581802668_1645581852317_0.2466307134156307","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1645668201733":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1645668201733","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1645668201733","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"be12b8fcdfa3d050054730af5a81b864a0d74f66","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1645668201733.tgz","fileCount":8,"integrity":"sha512-RPOHoleBEDPT0HW4aARURNfWG2pGsdqSmRifqfPOlUB2SU6HxEOJkb4p5dJjIlZADSwjmdnmPKCnBBrDfsCQwA==","signatures":[{"sig":"MEYCIQC3NhZCkO4WBXD5ST5YWdCvNa9FqtRqyjkLxh+FJXYoMQIhAOAu8C3ioPVYl3Fcz11gz+b77nk89SPP2qnK6cWuxIS9","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiFueeACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpm0Q/8DBVPNoLQIZHKupYQPhgp4Enhmw/fc+bt+8iM3SmzfNZ4gdXf\r\nUpWCy1Xnb9XSPUwE2b/iFZj1bucpAnIDNvYSNmWKg5t6znXEPxVIGrdo0AKA\r\nKdwAsN3w7OXPMu6fzjzf2B9O3cnWpFS2lXCCeeKiyoXMKkSlOlTwOOYOV5X+\r\nMaYnEirjPqxZZMTVaDLSCWNtxxrsn9r5J+gPLTDXmi4AXAYG4yreJHgTtONY\r\n/9uSAp8dagXAczYPNcV57MRICin0a0pm0wuSFkQct/t5cdmgtCyFFXdtyEWx\r\nlEDz2WOaRoIIsQYoKVUnQthSuQ72LWxpmWJGWdc0jPmZMzIdoJIZz9uSpsTr\r\nenp7INKx1oXDofp+9nWaYFXGbNcyXlEQZHi4p0gNQD7a+CVtd8M3Pvm2DOrI\r\nER+3Hm+LXT68ZSDbAbP9vMPBbkN0fsMM/LzHoPiCMmheFF0SOt8pozNAiA13\r\n1wxFmnzmxXtgomtBU5tUlxaTP5KENRVtQo78Tvfz86rL2RjFUdoaWZPmncua\r\nnu0Q9miOOgEkj7MNgFa92BxAK8ygEYHH6NXXDHds7744bLmnI+tdqsZECI71\r\nmV/HY0NSLIOdO8sX4cpfV6gVYaSahS3b+jBB7rO5cWEwWWL3Ba7P2+I6cd5u\r\nSn5+L72x5BryWdKC/AJOW5P60uufcSukvvA=\r\n=pejr\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"3abcfa2e6a404e467f15e2d058d88abca6a848f9","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^27.4.1","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1645668201733_1645668254054_0.48048301902655544","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1645668210427":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1645668210427","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1645668210427","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"78b10b9ed6fc4188014ee88c0502e417d5ef2d5b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1645668210427.tgz","fileCount":8,"integrity":"sha512-eUW9LlBmvxm4MfC9nY32ZKQnR8vuIoNS/6NXRzdqWJrJPv4fHg/HP73pYi7TUDEOKLMyTMP5n0PF/dKsN3hgyw==","signatures":[{"sig":"MEUCIQD0tYNKQx4rvEt0ZJBjad5SkVAuwwCEsDG+FwF/8p45oQIgCa1bMU2WNLLQ1cyRcO4ssvzLEO69zGR/bJsan+97CD0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiFuemACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpVNhAAhLdyqghMmzQJQgnvSBhoSaxU4FDvLFZM6pNnPYFwx5MpVNl2\r\nOIXF53gUI+Q2ilQPrY9TiIftfeU7ak8FwLLg0nwwbSOCDO+P7/+vrX8QrTuI\r\nAW9Avssu+uUVJzuiCK53AI7YPT3COXDGoMsL80YlS3YQ1bXQaN2nK/7I8Ylg\r\nF+K2yPmRSaAYhKtT3uEb112wh4hN57UQgKAHYH2+9r/F84qdidfUoJbIMh10\r\n70nC7gR67wKD36mYykHHrVjNDU5OjTC12FU4xwBLRMdKCjZpTUMJgsaTN9gV\r\nIKs6MUhMFVEXs+I0DcldzLktNZBtX2CrmriK8ujduHqxktz/g/YjAX5REIh5\r\n/5EscSZRK8Lbwnt8QHrBOxS/0DKi+REzSD+/eRVgyWu2NQ7k1b44wg0G0zLO\r\nzvs7WTBC2wmG2CFT4JJXGDD5rvYZvq0WQzrOs0RaVOf+sVhN94oWSc5ea2MR\r\nmRpPjhjN3W/keLVy8EEAWjaDRO+1FCeIxVjxUlByz19gsYvyClHAHmC7H2XO\r\nlmZ2+uzncj6sxs7Wsm/qmeB1he+SRGgakaajMkuhgIe5w3ukQ30FJds4/YTr\r\ny324PeqDA9PVlDS5csBUEY5egOPl80MSd+hT9Qfg67FES08nnGzbBe42PGPr\r\nogp19NNO054mXaKq0SRH/SY9mARcHQgnZlc=\r\n=6GOC\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4829e4652595412801684c9b7b294acefeb017ff","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^21.0.2","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1645668210427_1645668262150_0.06715741638299577","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1646013853556":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1646013853556","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1646013853556","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7afc1550b7801a3c9b999a88ee297a382d45cbc5","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1646013853556.tgz","fileCount":8,"integrity":"sha512-eX9EpiOlKyCUGbGBlErtk7/RR+HoYucvjmHmfPTsrmBmCMFRz2H6prURA7Zyff6bQJQePQpubtbCIX6oPQAt6A==","signatures":[{"sig":"MEUCIBB4n0fZAqU3QLO2fFaepH7hylyP9sv/N8Ps3JtyyOi5AiEAiQieZ/QsTPnL081uRn7OdNniKwH8XznPP51fNt5VBe4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiHC3YACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq5hA//Vm8GF3YKYB+9orQXjwbICvOlTGteA0z9PBXnlul8gr3U8WeG\r\nq1lX7sDurzrxYz9W0K7/TG8AhSa0hWkY6olyOmFvB6//ynKcvO/6NmuA0oNj\r\n76+SqK+Ij2BYqEDZTkUgPLGWweClwdCAg0yhDc3frz9vy5VicLqIpKyElvIN\r\n2W71eRTTXsIEu3F7j+fU8ZAdTHbsmdW3tvLF27SzoVdfvtpJXBgy26z865ZC\r\nREkMurTU0suLAQ+4EPnbjhaL0jnKu9nYVAK2uJyWOc8c5wrLnczaHGKswSze\r\nzIPzGWGK6X4QA34lExZzbI62l5RwPwexkUf9g3Y+h4sTKtn1tuMF04r2Knzz\r\nqjxoIPPHiBJeV/ck5Cj7cHzQ5u6sfMZV/uOojNd+JkfvAmlVmsCaQ3dmFg8V\r\nZ1xfI14ntF6+9EDa4FZav3bCIdXxRDSiGNNXibBFev4VluaUA05zoqhppHUQ\r\n2mtGJ1yymMlSqAcWuYmGnhlyJ6EIceaBcxg9362aBy4U0cM5QVSIB4RoF0m+\r\nvDWrynPsTEU26ImgU/x7r1dyW9tfzutoTBXzuTdSri0zjH13PKKiYStFjMsD\r\nzW1UDULzcLCjIOJbIP5X4cRYfCw5uGAkmU2+xWTMTIG9KFsK1GNBWtZwHBR4\r\njjfjzBYu9u4/Kg7E9ROMyR1Fjzk39Pbe0Ek=\r\n=LRQ3\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"bf70523110405d4d91eebfe3bf9f890266a0523a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.10.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1646013853556_1646013912794_0.5564084336037245","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1646272950919":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1646272950919","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1646272950919","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"bba0ca61da310d44b3156261c2bc88533d8e5934","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1646272950919.tgz","fileCount":8,"integrity":"sha512-AKQim442/4z0zcf9nk31ayXv02cSI4DxCVhL+Vc8hZs7U1elgHmlkuCrzlbyW2GwZJf4Y7Gkn3wozT/xWTGzWw==","signatures":[{"sig":"MEUCIBHmP2Q8cprg9t1UftGFm0lhm95xVEKVcC2gLSi1sqDyAiEArX6GX+CoukmodACOHH3evNEJt5RfeMQA660TrXBgQBM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiICHwACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq3IA//fYOZFrZ2KrHuNQJp1qoLPLIMpH8APdSfozSMTzU5rbfFvuRj\r\no7TqUBxB/j5fpLqyPWsiTD8R+rlFyQQxPlffOZzeyWk7URxFZ/KpAPyoSEGo\r\nfhtQH/+egXKM3ahU6dQQGXE55QdWmESx5TWaM8Cmgok3TS5yX+E2xN99Ovo6\r\nmIROaMRh3h4+f4fkXOzAqP9/x7YSFTZbpeqiTgLbI6nJOOmpkzYCax+/Kl1l\r\nTkn6A2xw7IeLqoTYCBW9VWrVwemrvTfq9ZU7EYUmSCpoW2R3shfysNj7Zs+X\r\nL2APILyz3FsreC5PSz+ouM66hS0IarlSj28rfJIOyfj97C/7jhli4GMJbde+\r\nEyLhx+6XGPRsAiZ0+9LNGS3q7pM4RiGys71FB2Ljrx8N9WNR+wWR0wMWVLX9\r\nlMTBlkddQPy2kVdqkA76WkaP2GTww67rKtY04Ubwve7ZhjeJnZTrj8SBPeHL\r\nSnMFaLMmSEZIViNy2vQWR044W8CCOQ/7PXRRXQb0iT7HMy4s2n1LANy6iF0o\r\nmZ3JNdsEmBy276kMFVCJvhPgCeDzriDeedf/VQlo6QVuxltyQvfEDGyZoN8a\r\nTvgsplg3Wy4229x+9ifheZbfzoz0Ja9BSUbKkukD1HrHzTIxhTse6s+ttS4b\r\nkoYMhWOV3QFZl9iReUwEZpEF+nKcQaBtIRM=\r\n=EVpj\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"491a3d47cfd8d4cf2f00d332a494189a8c2eaab9","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1646272950919_1646273008490_0.9512744929765524","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1646618581203":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1646618581203","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1646618581203","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a31ba31bb8bb25810ca285f76db734167dea66d6","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1646618581203.tgz","fileCount":8,"integrity":"sha512-emGq3wYhZMtHI/ExBtTzLFE32T59XIrJlt8mrSXtVNIaoBoKLGotiMEytG1pp1fE4vtSgZwFDdWoq64mYuKvgw==","signatures":[{"sig":"MEUCICY4yz4w/R5kdUBNmXfIot1f+G1QSChEAxelZVTL/PV2AiEA6Xh44qNWgQybBbdSdjr7mu8IYgSLamXSpEGREG63nHc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiJWgFACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqxvRAAineEGXDAIHEiIKKpryU0Vi/r1YPGXBSUig4mbY5R9g9Yb3PL\r\nfJWKRwQOOOwIR+5d2OFb6kqIMi4HY/O/t4dEoFzEPVsm3fil7Zow5Ltaq+Bj\r\nNACc5EydkxQKtIJDBTwoxOpdeN1RAcNDJWWgLBjqjpRmhANLCY+Zoy1Bp6WI\r\nFMJMqDCzvcnatTCyLbuKKSjEcBIr4Dt+Ns1Pwk7mOJoAz7nBJq43+GpDGwZ9\r\n89aBgPbClo+EphXjhpaFtE9YvNrEGv0Y9KrJh3G8sURqA6aSwvC6kDYgn97k\r\nUO4l5QnQOWQgaKLktmwWn+dimZ1+tckoDF1JDpzn5xK/7Xvnd5AS2zom2wro\r\nmYaE67Bhy3Mj3Gb6i1warhfK4g0Aq/gPSDMb+PYqcqwx2GiKXp3Q4PiaeVcP\r\ngScAK4QXKZ9pSOQ4RL5He91AQkR5kOUEJ8nYDEk1RIUAqjdKcE+P4ygjc0VN\r\n+6n7cDclrpp5ue/Dew71smU8hI7E85/nz7/xZciV//4p2oPUFdVBaOtpfRWX\r\nCaMfDAjGfN+N5aAGZnYwZ/Gf/rg6DGC59RgQDfrlBOnaV+jPRp49IyUsPWg9\r\nnLsZQlHe9rcwpwzcbz75RShELCABjLld+cEs+H5llJD0bvyQHx2RZNSRMvvB\r\nu7k+5cdcgAkDtdOTFgaoa7GL4StZ2cxvw34=\r\n=eFD/\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"c2e4cae85c077db7fa5ce0cb53fb8d90bf558a97","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1646618581203_1646618629458_0.12942542964638526","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1646618591074":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1646618591074","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1646618591074","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"9823446a08a338ad7485aed484a6af138219ae6d","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1646618591074.tgz","fileCount":8,"integrity":"sha512-lRC8vcCudAdbtdVLiDko5HGSKXs7CvnTz/N3g+z7+p1i8tEN2BYc9/8SqDAtyNnSQ1r4vM/hmMphm7Hu5L5a2w==","signatures":[{"sig":"MEUCIQCExpl4YrF62G7NVR+VexOb8qkbgiJwqLnWMmiVPt37UAIgXbbf1i3A3NAr1jLT3xHY7WdOFeHGJDpOz3f/NKN5zm4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiJWgPACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmobsg/+JU7Fp1ekbszUQfxVUCxu4tIuzi4q6w50BAzDTRug+i557kZQ\r\ntAe8hUGvQr9VtQVW5YIW0nqoLzbESkv98GdxdndRjpzLa+gkAmJNMkIRe7Mn\r\nmN7ASDMYAZBmEAiaQwOXBGB0Ydj13R1SjJbtqeTx1cir2YBmCGDX2N+N/0c+\r\nLmii4bMMVUzustQeO6X4HpuUvwV8lq3ZFIriCHfR5t+2Gs6I8/Y35VETFZoG\r\nteeTzcjnqx14f+inaFzqXtBScawcGPgEsttn5jhrGjPHJokeZihBYNmlHiI0\r\nwXm+M8eku1jclS8g4JRmMSXKiDkWgz9Gd6u9Wt+Y4CgRJ5xoIaQ24MrHArnj\r\n/ShgIkZ6dnZnuVvt/RhT95MC6FTQ6OR9LemQb3RdaGiNZhS/pQ2upUkDrN2d\r\nUv1NvZ42DAQ09eK3P55Wr6/v26WCi7UCvnc9TsbBCLeo/U39tVVstdB0UQtL\r\ns45k4HAx1aKVdsl2D8SgEekE2UojFdNdKbccCeyZavOaZ1qhbZK0/uP4A9Im\r\n+VcolPxALV2sM8LkRGI+lhD7iGI0auBOyO/+5ecCKNzRNQpslwrffku6tC8c\r\npZvzGVwCM/8yGZ6Syz1AYv6qXUKSuEc+aVQGG6+M1pXRYMwO/FSNDKEPWrCo\r\nb7QTsDv8l36TbVToBMpGseI+UIIbzxYNGnc=\r\n=rRm9\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2f79fbb134e22163a9107c4eafeaa7f040e62fb4","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.13","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1646618591074_1646618639753_0.15442009229673137","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1646704957908":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1646704957908","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1646704957908","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"6e8cc3bda3bfeef583889a92d5df8c6887026cc9","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1646704957908.tgz","fileCount":8,"integrity":"sha512-c68C4xQq9hxJZRec0ijkucFt7bIeYjIw5wHbNMHQIItjPuN5wCG/cpvXi4bDoyu5bFZoopqoSblfHHQXEJAK+w==","signatures":[{"sig":"MEQCIErvXXAgG2dDuNOIZsahCY/ZGK/1HnFzQ8YFvsiDltmBAiAHa07KkkSO5opuji/Pt6AOMB7aERIFuEaEIYn3vFJdwg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiJrlrACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoJwQ/9GoLfPae+CzOWfhjyEhznLeQMvbOpUgYOIZIxQKmA9SoXwVtc\r\nHpwzlS1P9cIMAkGNW8VvT4gzPYC+ufu1EvHSgNHWYdf+UvvUz0nOziNfYs9Z\r\n+YaRV/5SdOZRFRmROXyWp+WF2LckyRtN09wISCulQ4od52ltmCuKCKq798gy\r\nOWwd48mchpZTESiO3X565KM5xJyaq3hBAyfu5OB08r/QX1ThO2+BrXRCwVwC\r\nu0ug2sTrl4Mm040Og6howvuQC4H/cF3p51LNEMWc2QWVaRl7tDt6sY4jLqJQ\r\n5McM7+8wjHChQdjUd0B/FMEtbh4y1ubh6UeWrXuY1es0HW4xXTSyzTKY3erd\r\nPMbYCwp2wMFD7fhTUl2MQ7Egf7LIaPj0d7wJMT899v6WR2wHUNrLEwBMizkg\r\nRPyQv8AbO42S9z/foiAMydEIU2WZM5oM2hrCyWB9qPBE98LtRoOwzwSHzoP0\r\nfGZ1hZ+7q0Vmr4rHUBaLpCvLgrlocRywEbz+ERt5d1vWvPLhBZN0yVn17gzq\r\nanyiJBCby+qMFaEPNYWfp1PEpKi2Dhck6nWIXU41qtgL9E3tq7DQZK9ubeoc\r\n4pcofouDreSNeqycJtStxaaOt0fSAPIms+E4IucaBWcastoKD/XGx53vgUsi\r\nJB1wc7lJY0emxjDy4QdEi8jLhtCfTkuZFAQ=\r\n=napw\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"fca7ce51bb162b62d9f437edf949c1df1dfe18ba","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1646704957908_1646705003135_0.48560445913618233","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1647223402354":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1647223402354","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1647223402354","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"d9757888b950903587d1e97167123399b8edf38f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1647223402354.tgz","fileCount":8,"integrity":"sha512-i6FBa69Y70SUQ93uxP6N7VVwl80ismy74TXHHuxisMb3SFDnnG5CIB+IQnUB0nBecy41yuPZAwwuhMc3AS16ZA==","signatures":[{"sig":"MEUCIDIMb1MOb9Ihldd3MAhLQ+INPYuuwYZR74cVk8Y4riJHAiEAvc8DH8JfwFqEmZXCAO2CpIgG/6mX0V+ev0EmXRQALzQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiLqKZACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqJkQ/+PVlft/hs7Zeazh2Cb5Om8IIQN2efXUtMr8qBUjUVLEfYAerM\r\nGjxDlGEDurtXQBA42Q+VQUHLp0uN+K8IBqKctsTw+yb9sVDJg5aTIZyWahuL\r\n4IAs5raDmHvKuetQly3fzX397f9ZUR6wyfc3P8Y+AjDhTDg86VNT2t8rk7oE\r\nyekyvCHf9J7T8+ehLRoOvouAN8x+TbVbsPlr+ri8PtpVSKKSFTI/G5v/8CoD\r\nyrX+CZz1uYFhCuq2uph/k4eolqK1ycIdigmy04g2gxw/oqk73WJL6IWZT8T4\r\nmrk2xAE24lQRSVKKzG7mJhzgYgUht/jbfI9CtEzee0L7v4BnwmyyE8UIVcG3\r\nOVh0/9oUXoA58OUztPQf54Xd1c7u/SvIrQwhd3sXzXFvvAs3Ys6YHK4BMAKI\r\nMgFUj1pdwNSo9fhLrMgjoeusqJuqtm6sTR9+SMHc7/I/ucTYjnrq8FFiq/mC\r\noVNEXMepkJSk8R1gKdPOpk8Di0c3wC9K8GXzVdrt6YSiKQAWAX2gcOz3Y+HA\r\n5VPO17FKfSJCt8eyraVSPqG2gRI83W/L1ilRTAz+ucwQ3duRHaopMzFMBkER\r\nDseWJYzTaWyTO9BE68eV7rhdxdUISH+QD4R4teUglPtn/IzC/pCwaFm+HW3C\r\nYP3VzNcaOUAVDdeFKxsOXeWyMHtGpLdvfdM=\r\n=YIZ2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"7ebc39adf364916a997127156e088c082f09eea3","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.11.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1647223402354_1647223449118_0.530934790029902","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1647309860824":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1647309860824","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1647309860824","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"82a4c0442894a49e34ee5d050354279f339631b9","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1647309860824.tgz","fileCount":8,"integrity":"sha512-8aeg2BxBCtfsFjE/RjVgyHkLUWnuCI5kqjt3q0EaBssVkzUVghqLj1Ugrl/iQep7+Ru51iPNgIBx7Jrin+CFCw==","signatures":[{"sig":"MEUCIHhf+WhXpS2Pb39CNVxmLdu8GGltYdf42FqXsJTk/OktAiEAtrH+bEhRDxarR09Xc/BXTURUXDYGtC2///Ic07ZdiDc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiL/RWACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmohGA//ZCEJOPdaDBmhN3H11bFL2p0pVQsZYlo4aEkSkgvGlxM7r3K5\r\n9kiHs51ptKuwF4TVyf2BlHOMxGuOztQ+ldKHqSTNRW4XDALRxO7t9qZrO6by\r\nvUhttarM13ANrrIY3alXElXmsNOz1y6R+iHIbfMGVlP+AC/0Jg9iwXW6Q7zG\r\na+87lrEGAzWUZ2vnefUz2WSMW11gU0/80v1okvHhX07V6o6bFPhyOXtgXgQv\r\n18t76cCbRGH2Atol1FGiAC8tv1FTCsi4q9KoqBfNQ7mEJbKJNkde899ljeml\r\n2rPueNDIwuH/28OqCk0XL8HAKSTXKva213Kf3q7YrC0QAfER4aBv52EGoWvP\r\nfXQC8SBhwWiTriAVEZWsVu0zKWd6YIZ7JyRCof/jI+WU3fM/tganNn/CsYZT\r\nX4rwz2CZy0glZviABhq0e2muSv4lILbqbVbFfpJuY944mQ2QElCf1OV9t4gg\r\nfGo8rD/xLbFc6ynJNr0R0+SPedFRY1bXRphrqpStcF5ndJw3q1+X5bfq+Nt7\r\n1vIP8FRM5bcoo2GPdepDx/s+5D3Z7EQdgdGEeQ7tCSFbBwVXAvezNQNDVl4g\r\n8sOJS6WN4ZMXCotSrWJq+iihgpUJD9QAwvivQTsQBlE0Elo31DpLML28bTHp\r\n3pcwAOd5T4azi5Qxz4JkuEufVWVsTXcBHwA=\r\n=kJIY\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b8b710f8c2c9af4cf3635eec49b3fda8f3d7cf0f","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1647309860824_1647309910064_0.6616078528965068","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1648335406187":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1648335406187","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1648335406187","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"d71ef489d2dcfa4bf427f32a35d35b05adbc6cf7","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1648335406187.tgz","fileCount":8,"integrity":"sha512-jwLxLX4mH7pBHsu3oUoby/Aw7AQkX2c3mW0s6+acp035/HYiyjEoB+2T9zEp/eUVXXE9nuy1Me0aX9CpimVUGw==","signatures":[{"sig":"MEUCIE0jCJ1YEKl9MAOHV0NyLXYGCBX1X4vjmHG2bq+wLpMeAiEArnkjfjxa6BqiIO3M3p7G3nKacBUbLl1S6qvcBwXC4PY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiP5pXACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrZQQ/9FKbznXBzGMvvrgdVxdJqPqVKYagfwfr3Z9l5vKzqg9Iywg6q\r\nAAz79+8X8xdp9D/cleBLWWZzEQPUio0hQkp6M6OFjCqVs/XJXDCCbsQ9ekXx\r\n57kA/FAqo8xtIYSR37Toxymz75uwIosIG6uwTZaGHNZz3/W5C/qT8amXT1Eg\r\nNr8wGzbtM13+BoxEnp7E2TnMDhgz07nfwGU/NKyFOWDD8fF4VyiK121kLghp\r\nRFgaAZD5ksbvdNZjSXAa5PujP+NiMB3JheCAaZwCVNofhHjSTFeKV/otmLMO\r\nkjYYNMsjxwEYdbx5YcGC6YbVpgj79Vpz7vGGHvXb3h8BBrSIOpjRBi5Qq4h8\r\nZgEpCjaZJiYkGJ0YADb2qrVBBpHQNZjJdmPnVxveR7rYdRz4kCm0CHYf934x\r\niE00oq8UxBVG8O53dlwOm1gIYEndKTimTAGURsixDXXXMonVhqCrdzHyT+U9\r\n6q4iUiD1yqDx1Gj91vTC9M+m0C7msp3zVat+FiVm20rOEtEZrN5pL9BKOB4Y\r\n+iwSNl1ARIbfUWriDMRPNRDbsyiclOFarTJO2aFFd38/6zyezqHmKDx/Zzu/\r\nD3x0tcEEEN8UYMN7qUqxgTinyIy6N8XWLG95dRbMHBgneQCWkMS9A8ODR8Qe\r\nZf976zM9i7219QSI7uec1LxX8eDQxpABVX4=\r\n=xm7i\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"e18b0574ed732dceba1eb9eb52a6bf5d21983c00","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1648335406187_1648335447471_0.06823660828286737","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1648432949467":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1648432949467","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1648432949467","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8f92ffa37ee59bce910196100d914e30bd2b6042","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1648432949467.tgz","fileCount":8,"integrity":"sha512-mGwVXNjoofe/E69XiOk6C/TDQfccol3eodD7HxgSuXXdWvemaCQfo+31zSeOxeAEE6fn9R3svzEA8SELh7Xn7Q==","signatures":[{"sig":"MEQCICMjix5q/JCMmjtYqcM96meI8eLz4IH8vxG9lvCRDRTHAiB0BBUZZK8cIyY5aVOPlc5XAk5NmEyZSAT3RES3rQNoVA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiQRdrACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoQYBAAi1Z4Z6ftpMOhLhETx/GTTbUNeufzAfsmKumGyOD34h2zfVmb\r\nPQYh03NDEK464EViAHYtRvndwPZcwnixCCxvMo0bH8wzVPc0qS1XfsQsadwx\r\nGlLQ0XpGYOKGlc/HaNaKOVFHr60oQrzrc5rWCE7G4oROPA9mJW+QcH6LHElB\r\nrYuBgO4UvEA1PGHES4cUIfBtANwxPuxAqhtOYU1RACnoXHed4SbrMu0ii6Vm\r\nApZ0XCK+vg1NLdB+QNYr8pCkBfhEJAV2TIODdR0AIW1cvcZppbeZ0qAJSai8\r\nmx5q7vbfcKDUV0ClYXsH5fQtIvPz3LmBK//txQW9PcPMBs9yaGwmmvrBH50W\r\nGvqSxEAaEUDQsjQsDvxLvzI+P5gz9D44HpQGFQmhiK/MJtPrRfjOYhmd8BhV\r\nOB0moChuqvnik+sf/vBiSJMi6USD4ULxGRW0QqXfrJAz+535EZfeqxLJQJfB\r\nhCE6SEMydzurExPpwvpHPeeC8INZA/V2KCIQ3NjGsMIZ+TJLbWcHGcbtAaw3\r\nJ8lXvpwH3Qp38vyYHaXjgnVxHO7AbOhvSfI8TiHGV7WbGAmOuTCEeC/QjEED\r\nJ62BNdASeufld5fWlymRIBhxUxflxRoJ3Sux8Ge7UawGFwhxuWqPwjK8bpzx\r\nmYji+TYFKSAu6jA0aVZkNQP9hZmi5Rxs368=\r\n=Eb0K\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4b587588dc7f1dd20f6a89fecf2923c846adf764","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.12.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1648432949467_1648433003771_0.4618451966422137","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1648433038403":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1648433038403","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1648433038403","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"bc51f2094768cd259bb5faa3a63a07925cbb34da","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1648433038403.tgz","fileCount":8,"integrity":"sha512-e7OXmOwBk8UvM2o1j8TG/foO1DzH7/dRh6aIMgLUHaaE8UTe0oFTjZy0zEpEF/DzAd/iTanDXZzR1VLVwaNLdg==","signatures":[{"sig":"MEQCIB4IoDsDarwc1y0qO0a2HGXRR36o60fc4nmhO11TL+SOAiBc0nI5H6tSMCys19i6g/JvlNuNd+Ox/xkifI1kJXQytw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiQRe7ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrVDw/+IrBnl2gRePWUHUmWVosKN6xhUecqOfAaEKkp69wnkRCJNvUi\r\nWLVeo9gkgDE8jVLH/WnaS4O3873NT5mBHKFdiwzrogFJFkLjoEk2cPd6qYvs\r\nLideMLuoivxyIjGF0BJTPKYWxMc6h+pv2TLFK40QrHSBQm7GoT5eRg4oCt12\r\n0OaNZk6Kh1SdZNSa89FC3pZ2Na/wQSygryVt60H5fC8T8VNxroI4zElLpZPO\r\nrzRK/S5t1Z+IgIOS2CrdKD5YSakRvd/pEXRnkf3Xppx8N/DWSPeYJjnOz94A\r\n4I6BXaCavNA08VhCu1rUwFmXXZ0jKsYAnVhMyOjEyAvf0ZR6REghweBNuzNM\r\n1DJ143yr/SmQ28vD+VHdHHgKAYB5PTvDkU+NC/8HVScQKWNFWH3778Qf+SmW\r\nuyQhtBzHq60zV/jhMLJK9dBxCaUFUqmS3v7P6oC85GAYsBJWW0I35jR0e8ul\r\nvPe959bzrIIsqrJKzHt+FbuOvgWl/QYOtdlE8wiwJAKLK/FQxUOj76jgk+5i\r\ntUDXCduSVNiezye45EMhsWOFbs41RFXoyY9+Jl8ECg/QzYj0kTpgYgQHD0EP\r\naSlyP7huGUmoRqP/aNsKHXAusTeKtI+e31o4P6UuE1SzJ66Rg9YHwJ0MLNlA\r\nhedy95aaeoeJLyQt81b7nJSfA7duwepHsMw=\r\n=aP+G\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"77ba3f5343ec801a5d36b7c673cccfadec352eac","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^21.0.3","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1648433038403_1648433083107_0.06177154512849725","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1649383413667":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1649383413667","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1649383413667","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1b1c8e87724bd35557c4f2181945103cc4fb7d7b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1649383413667.tgz","fileCount":8,"integrity":"sha512-nyfAwsk7NMT7aDzwaarjDlbRamDeUL9Yl3xzHr3gFP5EuFgZw4KvgW+wnv4ocZjf0h1ZbPKdmvAnTN6xo3XAJA==","signatures":[{"sig":"MEUCIQD6FwK5qsjDgwVqpJ67vArhrnM54MuboyTrkS1LI7eIOAIgCX2ZhWyta6oZr3kVPKsqD0BeOBbZRoqXAFo/2rUAQKY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiT5gqACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpNaA//X2ygYeZJwHx8T+sSeGLXVWkOmjiP4N6cUQAhfhLVmDsS6eMr\r\nKwWh7XqjbFoezlk9SvFq2ibV7/CNygGGfSa/ljZ5g6FYJ4DO+47Lus1H/LcG\r\nvKoNiFHNJmv2szhYkVNdIBRdXKAfVHhSHXVS6xUbgwszq2s5eImI3YDjTjQI\r\niwMEwmFk0aso+D+1eSzDmuujYSZAZRlfXxFIMnPSpm1G6EA/3rzwDie1IPC8\r\nI01P2s11hnnJGkFl825qpgWsigtFBtFqthbdXuE+8QXsw+tBZa1M+/RSGVya\r\nnS0/zMs/Rnb0Om6mQ2X5sX/DyKb7xyk09vu1/dCnaengTU9O853TycRAPeQY\r\n98oPnEvXqDZDs9YcCV5FPfRnWnp8rGQx0dNUzqAcYhLcoE+jkN/CwZzVgxz0\r\nkMJDMPF7bNqt3ynCV6oWtwaulDxwam3fdbjZVS58s9T6ueMndzBmBVoq5tel\r\n+jAliyYyB6DHpr21i/5+y8p6Uf4kwXDvpTixjsquofMF2xnVHhGl+Q6Wbnac\r\nkEgzHSERKF0+jmq6MqCsoNwZUtBPwI4SYJ1BUfcjfgqRlJi69eFxdOw6KDNe\r\nb+a3PzSgojqd0ueckNH4gjXbFPA+lZfqAcBX6G8oB2jQoNcX96U4fLve2Cte\r\nGM4iwgWgWgxyF2+4v8KHc9CGvbHgjSplXWM=\r\n=zyRv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"945dba8a4e371a1d06da7d4f5de3e4372aaa9e2f","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.14","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1649383413667_1649383466102_0.5295412961757731","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1649642533205":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1649642533205","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1649642533205","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7afbe287d352b81f850806590c06c490e40402f4","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1649642533205.tgz","fileCount":8,"integrity":"sha512-CBL2ABKgzoGULgygwLcsXD06yXnWiLymF9rjA79NZnRhOkDnu15N8E81sVcnCU/gLEHOmbs5GWJMl37FICS4Bg==","signatures":[{"sig":"MEUCIQCovG32g+lExa80ATzBpk3rzccnHViicF5afs2dwSJN6QIgWUmXpETyqyrhv0CIRD76LNt7a9nDgN7WRTF+/dNRAIk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiU4xYACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq65BAAklH8TKJ5fTzLnhcFvgHdlvTrnaFNF28ct9c/X0iigb2EjqtF\r\nXb/AR/dyanLPwK9zpKkjLs3DJfcME9y+WCsEz4dyjKm7A6ZS0vDFgJPYqHHV\r\np8qT75Zg0lnyK4aViCVAYQVYcdV+PZgBij911hFkf+8AhxsYiNDjLObb4ob2\r\n0cjmyjuo+vnhb22L/pbPcIkYWr0HCwaD/OBMyYW1LIFoQfba6BhAPmSCr4LO\r\nlNw0gBVZ2lWXG0L+NzIoecaESDOOUyxFmzCEzf8agpQEl1es65U4bqTNVAyW\r\nDabi1WiAZRakWBo4J2gKhaHcRhogg86EKQWFJ1xd4h6Lx5FcCsFcpiucsOBD\r\ndlpTfXflxw0DCV3l6cD+lVypkopQylxZbC1rj5o1NEo3TCwHI06TsW2VXfTe\r\neJf8S5Z2eH+CPQyWpo87VpMxH4i7fBlzTi9cdJ6OXRrxtiJEuoU+XC+sEk7W\r\n8SQH3FcHWmWkXhPH9FGVGrx9oMHZr7pZ7QxzMTnPlt6+Uj0VwCorGTFlFkSY\r\nb4jYQxlF9rNb7hTB5NGOc73D2UJRAwpmkPKx1KliFgBj1foJm3QXeIVnSGzn\r\nXeCrB5NnyPBczHqlDA+/v3KwcGTuoi/yQTDvH9htIrPE51JkbKQWzLoFjsBn\r\n/YTtn4Ytr83vRMKPN7Qg5bYBRNid6OEQL3Q=\r\n=BfTf\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8bb93cbc8a8b8fd74a78a68d8af50a07bd7d748c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.15","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1649642533205_1649642584093_0.9808299922051367","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1649642643089":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1649642643089","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1649642643089","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"819dd25bc5b25484584cbca2e53d4c6dc48578b6","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1649642643089.tgz","fileCount":8,"integrity":"sha512-goNpN5spOu8iM4kqkeooNteODIoJIpICKgatVebnm8FIoQbfz8RZh/26V2yjGL1MYTcoYBjaDQ8orKfG4RwtKQ==","signatures":[{"sig":"MEQCID7jxMv6bWORdcwxwanxHRe+DTJfFkWOK8G6kPjCRQxHAiAUl8+GsG8f1u3UmHlWUT3pHwOaNcdXS1twILDtag7Zgw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiU4zIACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr8BA//ahIuEh2ktSXJ8wt2jkFpeeKTrb+q99R6urKKVkpBDXfUMXto\r\ntDrHDSQtOhtTdWEek4ok3PZ6+N1Wq4gd4ovspQpq7gIHDG+1pfShS6WoH2tt\r\nkAGaUZ7rysI1Wa6Qv+FGx8e1pHN8Qet12P5GdvmHJJOfXBm+wFCWArKTnJvp\r\nIbI259e1Q4IqXkU2Eb5j1VhQsuH4q9JKhUbHMtxZevl2QFvbzzclSgytmpru\r\nF7LY1INlzJ4AS+eGr8Jk1+5oK63cBeqAIBuWRNVuOFa6RHHvYDfNo+rlSOfn\r\nujA92QUvNPVlGiHGiunvVcczJm6tk6uYIMWumBY/jZbECMR24BQPtUHpqk+j\r\nf9So5YxyUeUJgN2D+Tqfy+VWaCHNYsCW3o9byndltwWyVpakXSUlRJUPraLC\r\njtV7cks/4c5+BMK2HKm4g73ji741zFQ4xuu88J4xO9HdKkAzghW2Gj6Cyagx\r\naWiMfxnKHugBAkFG8c0Lqn4r/s4Pi0Hkgm5xAWXbHFYxWTebcgd6PAwjUH0P\r\nnICCVSj51+SgXTyg4m/PW0xxavdMFWTGzo8YOU/BQUm0g0piEFCxQ7xnMLqH\r\nZlyuN4cvPUowrVP2coO5KgDAGGDJiwoa8UsLKlZlhnzp0J+vjgxkw/61xMMA\r\npP7M/3W1nnY1Bcp2585W+pfygVb1K0+aBdM=\r\n=1GG2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"32abbc0f6df913d0cb2df0dbb38fabf0801980d5","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.13.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1649642643089_1649642696176_0.02764337694042185","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1650247441447":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1650247441447","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1650247441447","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"4b369b501db27633b5d3b2c8799b696321281e29","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1650247441447.tgz","fileCount":8,"integrity":"sha512-yUryePiVNo7yd/iSohj3Em+Evx6jLqQ5qG4Dm2PMqPfsJN9SgyjKxpzJI+iJEwpDauPzov2ZQ25WF4EnQntzNQ==","signatures":[{"sig":"MEUCIHOrLmRs7YgCAiNuOCvUJgti1mhoo88d0oUgrkqOLg5QAiEA2irEEzKahKJkNypIcZJHs2x5aEffJ3L7NIo2SHpW2T4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiXMdAACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr3QQ/7Bh2BMtvrWLbUGdGfOTXhhWXupJju1o65R6ENMf26maGV0geV\r\nv8BQNUbsS/HQNYtHEumJUS7NdbsCGGyVDUB2Zv6Fx3HNdTA5uWdUIy8ssVCV\r\nXNFsby7tN/xLmLalJbR7wGKCkYyLkohecYS0giG4cQOlCu15pw5MLhBkoWSI\r\nfSLs1c2GeA+runjs1kdXl+/fd5ZyAnvPNO6kWGNT5JSHVkheENkOgmPEYeAf\r\nx3/B2yk5+rN0zZ0KMzw8Zs0K/7wpg1dizLVaBtCthOBCTlrlfctMbpi/ncyL\r\ntftSi6gAicjCo4c370/WSvVGyCSODXdEAZAhFz9wEH01G6O9jnMVb6uH4G68\r\nuULt4bn3CcgillX8pelVzvKh0MZviz8PrWLAdAHmlQE4ZW7iuIww2HDWqqel\r\nRVyIBc3gsOdFEmS2hJUw2nU1tjM1NRwU+bBPTiwzeco1F8Iy51D58CYDbDQy\r\nqDJwMrB8RzK3ERQBtGneGSvpt7E0lc5EIj7Vj/1FYILc8B18o8m9OrC9rMhQ\r\nQE0xYSVJdCRKgEsYHx4U8LvE3K0Ic55fsgFt1Cjhqyahl97QLOkydVABX5Kl\r\nSUoJwAhyKMHWWGghd6Ob1gWWHo+suuyMvnNQ951+wvq5ujxvgEEZZ0aeUB4m\r\nfA11msZeEv/aJuTPLg6P3CemztDdsKtcE8U=\r\n=Dey0\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9ff84b6f63ecaa4bcf5c048421790b85f2944da6","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^21.1.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1650247441447_1650247488038_0.08316906532930513","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1650247487211":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1650247487211","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1650247487211","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1e5423e55e5836fdee4f9a65a2a9518d41e06cda","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1650247487211.tgz","fileCount":8,"integrity":"sha512-22pv1bi/ljcitHm9yewE3BeKYT+hQHHAna1TabOMbzMhxkNXp+QSExq7JKSDjYvx43P5u/C7lJocPrOkmvBW4w==","signatures":[{"sig":"MEUCIQDYCke5R5QPmHhiuP4X5LXQ1HtSRWBbDX5DIk0r3XE9JQIgYxFjMuGhSeScaATd0qEmkjq6tmQkGMN7kEIyQwyRQW8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiXMdvACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpM6g/+PVydVoyBQK7tmm40FMGT9oDliDiN/t4O9pk8CsOAURJ/hCKk\r\nSDx2EfD1qCuS2s2zZDtvr74aP4vLzq8NYPTc1GL8Vlbe5NF7c6N8zR4g3TBR\r\nPQZfgDmGwnbk0RxAh2y4Lq4SRYre843Ue4KC+Jm9tZa/9syaueMAo/Zw4ANV\r\n7zwbnrtOyTjxq0PCByLzWh6aFtN3pY3DtpQArzt5dwEXBZagIjEfYcbXnXo7\r\nhsSL+at0ynzLOpZhZRJpV6cXHQ3JJKuokWwHTWyXy3M/E9Sm92KCwvsTEl3O\r\nED5YjepwSJQRtqgJc5hiOjGgzbC0/L6SGXrrGMs9eoz0b0EUnwC1y7Ez4o6t\r\n+Z7QItNpMjyxQlva9A8cW9YY5L61LTrXv3N1+RL9AAEoJOlWMM7u7bh65XPo\r\nqvV9uMPtmh7MZVIBr17rkaTyhJs/F6pjn9r0ThhViVGoF6IgJL/nOvuojSGt\r\nGLO8bH5zJePwyzw/Hb+SP+kan9MaWBTjwb48HnC6LgufVmYydwyWMEe2a8ac\r\nusCH1duB6UZAZHaCjL7Ew+03FDfJMZJetBj4G0Zpv+HbsQECZPqKRArYLuGn\r\ntXzrMLh7nEEAQuijvIkCqnwlKg/3qu2Cg+pZIwJxwsc+sfRurf7hzAmHGCny\r\n9fV2/sEgphlzQyau8EXlJEHuksWxQ4IO5tI=\r\n=SQj0\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"391d69e8072ab2772ddd4d88d5d7056eb764d78e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1650247487211_1650247535207_0.10907287951568878","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1650855285310":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1650855285310","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1650855285310","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"761590d58fb0168cd017ca6a48c178b1ca19b0c3","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1650855285310.tgz","fileCount":8,"integrity":"sha512-9N2QFv0bp9vH+m2/BH9OhfAWSsxUX72THtJAq7IKOnlJX2QFMRMZojPOV4oUNxFpHQa1rvcam0IaD9l7HGWHtw==","signatures":[{"sig":"MEYCIQDUzQ2j6suOkglYBz3uME2tui0FLXqI4ngZyTFay3peuAIhAMObtQS8bELl56DIAr+mA8NgUfnRR7Y9+CxhsJDttbdK","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiZg2wACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpivA/+LQWyQsTHuQiUuVTGfmjdjdOe9C8nd5fTdl+K4kVZYxEvuxzO\r\n1/Bn5N/A4P5CsCPAh5Ctzo+yFBRNSCDp+Dc7HM0sxaA0jWUOL16HIHoMHPUb\r\nEJYLh/6/IzmxsKwa5HyFXll90RaPj/mw6Mki7pdx+6oejbnx7faZMaQ87mqm\r\ntseFjkVDSp+JXBCqPCmiLUPKkPeEjAyEgR9HTeegS2kFKP92DLyk+WhtBnr5\r\nyL+p+ifQnnQmIS7nuIYVX1MC5YHwHaCLxWejXGkAf6LzzUjGdc5eTpyFIUoQ\r\n7P6MlUTqvzZadmrI+1MyvEikV9Ek/YrbYcC606V4yAPc8jKXoJa3raT8u3Hh\r\nwmuVFHJNWLNwoK3EG/ctl0j7meP6yIoLAbGCUlexJ0cHOPpKXsSsEq3pIUtR\r\nvqCbNR5CkqVr+BD4JT2qGfEef0IOdzw+CkfE/DalIWtT5oDjsZ+/9kiie6im\r\nCeucixUbslvQ9NHMGriEQQJY+mYjF9PHvDAutTCREpypRP04GXyesBoLzl4Q\r\nWO6WIZetTsg+51LTNFKMs6H66scCfUivrUTyo7b4IzKyDiO/3NltafpzbcbU\r\nQfYqxkuGvcOgpsFuV3URrjpM/FLTaG+EvhzxLoKvZGAUwWAf7Y/gICVVPNgm\r\nGeolbZbYxL2yaXz0kPvYrAAyBTLHB/3TDYg=\r\n=UcOT\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"83dee83fd141112a2e9daf83776447801ba76c32","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1650855285310_1650855344765_0.24803615024899184","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1651457039507":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1651457039507","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1651457039507","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"626ce3db72222180cf0a4a5e2200ad0ccea3006c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1651457039507.tgz","fileCount":8,"integrity":"sha512-CBWDgufrcjWHTrLxEVUXsUfMmnIfmDW+PnG2JjIjWgHDAdvn84RWWE0+Sj7GndsaarVUHLX0ZvzMPN2yowT/AQ==","signatures":[{"sig":"MEUCIG6IB7nF6mx5Qxwrqmh5v6WG/DWcbc7I1XgOGGeqRIDUAiEAqcO6S/c0a91OdD2Xhp391MvmYlfHrC4+W6LtocXP5YY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJibzxCACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq0rg//UupwTeAwg3aRp51Lf8XkkyHcbOu4wF0jKpx4ukpk46yx/wRQ\r\neOlVdDFRwMbwri1Ttez9X5mrEnugaRZXLMt90XGHVAzn3Z3s6ll1xQUuohBp\r\nzmZlU2dBFbRaUhhCM13jXvMVaEcJvi2o8ZVKw6cmCeGWMdUuwVKYpWHg0174\r\nTNyvnTxDes78iIr/WqDxzvxbADiOqNuqUAfqNlNlelE/iJHWQojUzpc/4OSt\r\nT0vwxLZ6MO+82tUK+Ylwsp/P0/voyCqazWErWslG6pBgkZ9v99UabF9PXeW5\r\nzyZGWeT/jyP90FnInbS6I8Bn0DeBUnzb54oMvGPvDqpdrmzFFgjiqbAtsvJB\r\nyVJpsNpaYtVXXjK34F/l6jW6TyQJadXwyM2ZlbSk15Y/ewPFghE8eqxjm56P\r\n5vWKUG2z98IbAmBRysJ3jlfeW5egPYFlJCCYrAu2ahph5mM5JlWZyBp3F8Kq\r\nTUhZnolFQ6wCtLRgnrJOzCO5JOtPl92nzwkS4bBMpfR23qCrbp5LS6ThtcxB\r\n13zJUb5B2yYu11S6tu/bADMDtqF6bgmpRW48cY4pEjL0c9yfcdzb5rTIeXfG\r\n6Ftul0XM7Ualner60WtVbyUd4Y+Ca6owLpRccAQrr7e7VMcSRR50JNy5zDEo\r\nY87OojzUWgac3pY4S7h3EGQsbIzt/7nm5Kk=\r\n=/FDg\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"afcb43310b04c6b82569f88e5ca4f31e53348eb0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1651457039507_1651457090628_0.4426177038707253","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1651543362807":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1651543362807","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1651543362807","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"2f39799b9f85730b2cb6ac0a5cdf7614fbed88d7","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1651543362807.tgz","fileCount":8,"integrity":"sha512-A92I6rYSvqCLXRaCzyRPxqY5iThGED4ntWWPYktdDTOPm6V1QbMpxKB7nAihVmirrk/lzt5HRgVoaPXSPzFYPg==","signatures":[{"sig":"MEUCIQD89e6DMIMSDh/XrZkjwWDyT0dO1+GaeUs0MMvjksUMFAIgOteQikuWA1ZCD291rMxwAwKz4YTrBJAeUDBDSiYqG9Y=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59947,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJicI1zACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqOeQ//Sa8W5zg/AYAucSUY3uE2Nr6iKHJwrEQJ7doNu3xvKGBNJrew\r\ne38PSoQTBWPCI03iHM4TxyGQ3s8rpzPZ6k2e5uurhaJszE7JVw8bHwhS8XBl\r\ngGgkm/ejIHL0SOFUsUp+bYKXBsVFlVRs7BIEUz76WQHabA577CekmMAn7FTb\r\nfn82zWqHntQI1TPqcH2vn7U+kXGPY4Mp2tM/fp70msQ/iGfRFIapuRUMovDC\r\n565/4P65xwZG60Lp/bCAJfPHpy+cJ5nZ2lFz41RfMpOWkDkCAbcExgcVw7d+\r\nYdSYyDqFG0/PrLBy1WsgdR6BaYFKk9so0PqG15yyX8zEUtpl0++aVXP8Dldc\r\n0ZVObdfzXcmXWlF4kqiD4BWTjImQrNzvrQ9uZUrf3D47WIGEn/JHnpkG1kSh\r\nQiUqVOFaSenV8SN653fAnyf5V4qsUIoNEFG04SJC/mXeWf3pJAldwJn0/A58\r\nZjNCHWXghgKCh3M6gapG9PUFl6mq4pyXIUtCm8wCUvgP2Q2S0RqnKD87XqCD\r\n5+Uf9dhNoqW5Iacyal3D+jcduLwpu6Snnfdjo77oNBEpEdh/KDlhEP5YjiC3\r\n0A7ieAAROWM7hNRLBASw5K8oq5qOVcWf5ewIm82sEWJZunYXdLPeLwtmEe2q\r\nshwEnec/PHi/yqxEsUFlIuhOG5Qez3YvVbY=\r\n=C8Nv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"fc95143f59195dda35d8443e05b1e7057dda5ecd","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^27.5.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1651543362807_1651543410929_0.029347631185160372","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1651802517935":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1651802517935","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1651802517935","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"d70ebebcba2e7b09f41b9f521bc21d801c3e50f5","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1651802517935.tgz","fileCount":8,"integrity":"sha512-SBxD9dUtA58Zj0/unse8BrWlnVhrREZIFIYuSeDQDAY8HGY/dOpYlra3xnbHq/fWlgyhyFBZA5l5JGYt60QQXQ==","signatures":[{"sig":"MEUCIADpN2v+0xktv16Xs7KXTL4OLFnxD5iJlwwSUabClnW3AiEAmxRt9V27xsiSyxel/wfrILMc2NpXQgaCk9U1jnSGmzQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJidIHIACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrf/Q//bmBV7dtkD9dGxxTXQe/u0rFKv6guiKwWXODb8RIrt9wOyq4H\r\nP1ABpussD317pyUwWxvcs7zKIpZT7MM8e3L49a5pcFBoEy2mFREr+X50geWa\r\n5MYK9QKb2Y6d4CSbTQdAzpwK2nYD9+cnZ3lfafBETUNUMtnvN0ZjCCGLlbUV\r\nEynFj/30+7jVXT5r/2YPBxLkOPtGDUNAjmoOcSCN1ugBdgRmY7yXmGB+NQNy\r\nxqr0ijuM2/SHk3SEbVRgPe7iDCEm60eZh2YaEQUkuiazN9igE5gQW5XSEz40\r\nmIq9T+SOoqZc1xIvWDou4IkSAIW0pBidnfR6CnJWLJJm+CLB21EWRL5pJfqx\r\nlnKejGmmUd8/la7HxfITXcf3vWSK3Ie+jSkkXh5eVfQAZ1t5UiXxTBDF0ja4\r\nLGRqhzc7EfzQ5kSnFpNOqpZBjDyLWWPO+OOIcmw3ywer8hEzpEqlVCHSiBLx\r\ngj/baRKtfC8IrTIXvIBndhMx8ld52fhjiDZ7h71l7GxqrvYSQzVaBDhyKyx+\r\nPbg0TQM+VcA6+GpNrfSZo4GdWKIwq5oCi3+J19smghQy7iVztgOBHDrZ+4y9\r\nFVgxvrvj3/ndZOsRlCbqmEGSPRkP//yCMWbqdgpoOiKwkuQn/cIc4uIrUAjj\r\n9edGfnYxg+CS3142+PAvVCl2sg0hbmdvwuw=\r\n=9c8i\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"5587dce60603497df0829acbf2fbbc1357eb229e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1651802517935_1651802567966_0.7635080961244891","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1652063188729":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1652063188729","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1652063188729","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"58498f9f1934ae42417f63be385ddd5bcc88f0d2","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1652063188729.tgz","fileCount":8,"integrity":"sha512-AAUF38w56Gl2rJvsXHi9blX4hrUwKgoRiZ/2cHAdVxJUG9Equ/X6qlaKkEhMomAzcr0AnR7paGWw61k4uriaoA==","signatures":[{"sig":"MEUCIFq7i4BYexzRA1EgJCgbQLcvUjbtGJzePFa70hxJTZNwAiEAlExXRZQaY4sUyfPtTTD4+wMcbno9adaF61EDzyVZIRY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJieHwCACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpKrA//dK0tt43tchXcoimL2n9EvzyUIXMDyjZ9/LAwWAf9tMD/DvXx\r\n1hk6hjeuj9MZJXXl1ahAsPUbMUf6iM4OQymC5RQHpc2tFvZxBw/RG5OnyiYC\r\nOOKG5Pz3QNt1mr0hDgGUU8n9j4SRNs+pYtLbGCnPuG0O6bdX5Tg6pJbHmE54\r\nCwxGhin1reE4VLi2KuuMMeFa5BrM2gSbZtyyor7ArBAH9GfudrgrKr+OrZwy\r\nEVkBv961oAFL+hUSg07wptZ/89USudqhEJBgvz6Qy4KV2lhgTqgVtb18ndGU\r\nWL/iqULlcSruz03fUCmkL9LqRjs/EmI/COSgzDjTAt1GhlnkUYx8uo8mrsUs\r\nhYpiABteqFE+1coLfU3McFod8b/JXw1ZAIhyIFZIc1Rzb7OFIEWx4MkCf0KV\r\nsMm2XsaE3N2Kb2ZfwklGSWmubCYCvwi49nixcDc5tY8FddP+1ZwLJKvdQid0\r\nrjyqJuZzxvLQRVu2eSNBzlOHFCZ2u4OW/qbXXDGWLU1F/nHd2Sv76jSQRs/D\r\nWv2148RB1+SB1kIkd+UYvCFAkI1tMoFDIXy5XnYs699ajy2a/eSBlJksCpnj\r\nBoM8Ay9BNONFF1w8xMsZcJ2Y18eOKMWI8dAPw0T8S8ZySe2oE91U0TMjS6CX\r\nMZ23N0s9PN+f+FDxbnRAYGJ0WF4p7PoUH48=\r\n=gVgL\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"a8f853b6027aa9169b54c282e7e591c387190574","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1652063188729_1652063234151_0.9562401571151022","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1652063174415":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1652063174415","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1652063174415","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"176a9b4815d8edcc88c311c1f80949ae2802f2cc","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1652063174415.tgz","fileCount":8,"integrity":"sha512-3PBVBxRTri4HEBaXVPp4zI/39fyiGCJvg2/S76eitgWMAss8UfINPxhT5/73YQ+ZZzMXKZJRtGdNr99kcnUcpg==","signatures":[{"sig":"MEUCIHyXVq6cwjDlnLkf8tkCpe3YQKNZRJVMKtDxUhVp1cWDAiEA25FJ0VspSApnrkQQVk6NT4oU6cr28+mrXovWfK3k87M=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJieH0RACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoQCRAAj7M049iXkF1PybC7UlML+yEnFWDQQVkL3+R/SDTDm6K4nmh7\r\n4vikZ9bi7u3YMj9iq34msQeOBc943ZAFLnyKqE6TSb6CWRLIXX42dZ6+Rq64\r\n2evmh1DAudUp2+7JOvtNPh5fHRbl3aLXsS8vyW5vGwNz/RoKMoNQevi8nMXW\r\nVAs6K4iCEf+RuKMt+c+Gyx/W0KSFepRAHN8hTyyFagWZiR05iOZs2owhR2OX\r\ndMYYAspEuXaaw3VqoGqTdsmJ1G+07ERH052aWhSZ5EyN0r5xkcg+je4CAfPN\r\nvNQK9JCIbVtSCyQzleVgip/BAtDlO6KJfPaH3CdzEQYQTtXXWK3DAk9Jo1Gd\r\n+nsYDEmwZx9KboPPus1gJkB7iNnV47K2Qkh7sUeXaa/McTfgt9WejQG3BH47\r\n+4jbGtPYfoIveBn4axM6+68tPgJ5OtCC+TOda9g48aqqKiaKIs6IZZvVs8x5\r\nfJvlFJef8DNKXRbLPRs2mRxiBN9mvuXKsqV2P16Ny6NdN3HYuIlwjjuj8wHJ\r\nwOHD/o1QX6TCXsQ8WAl1m+cPAVJjBI/Aaz/+Gl9lzuK7J8/iZGUnJGpObRZW\r\nvDaFIFBmxB07qIzg0/HxqJ/eQB8a1c6df6T+nJK8HArnLnYc+Zr7C0/4srZ6\r\nBldM3uLmXmcD4iLa1ldQ7FZ/v7QSSN5++hw=\r\n=JUou\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"54be76d0809a16408209294f07f7e04a7bdef476","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.15.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1652063174415_1652063505265_0.8597154257168911","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1652666579732":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1652666579732","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1652666579732","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a73560c4cedac59ffac82eaf0593b7b8bde7f2e7","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1652666579732.tgz","fileCount":8,"integrity":"sha512-kTED711zHjIlesNg56suvsAtXnkmGgwsBfsfvRnWFtDbh49b0VsA7yCw0UYfXWrktCXWDfl9VhY8J6YjIRn//A==","signatures":[{"sig":"MEUCICCjV3trogGtAD2pZgaMvkQyBbdPaXVALHEy+XWk7KeaAiEAy340bOgm7Mtkf65hbyM5+jNmqh+36EwAYXzeKP6aMS4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJigbEoACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpMHxAAnLva/1se2YxEs9XyukOZ7Oqhv2nYL5JG7yLgt+qsKT0uMvJm\r\nYBouc+L2StMJ7d4/+4jn/jDr3fc1JVdfSJQXyDcQXmyeD9E6PRBlYedEhTHj\r\nLmnjDVSL0mSRLpFpvJBFs9iXkG09tkgrB7dXGyUJ0tw50n7p0F4nSi6u1vHI\r\nJENPC2Wo5gSF06qBzLKG2341SiMD1SMrE9zHhVKvsQO2O7t4TRDUo79z6KKB\r\nqqH1GwdpQJcbtbgKr9yrkP1RcKHh22KnxbQm5OpmsJhUVUZJqVUJzjNo/BeC\r\nrTGhwNyXw1mG1fB/DxSlPSwCg5ZxwzPmrLCT6I0Sli1iTCERKA7mjNzRkif1\r\n5OWgDAfA1k7Oz4BMp/+Up4qDktvfAy4jx96RDs+pXOrQX1fkLLXTxhRDFOyA\r\nZFfVH3qc/KfFW7i6ROFrwgbcIJORRxzFUif8MrrZl6KIiozI8McRsBcLnHv7\r\n8ZZp0upoDVnEs1/vojqwy7lhxkFbXfAtmOgev2wPSJlZVpjjmcY8iivkha/Q\r\nFgFmDO1fNe5FvKrda8bMv39bvmdB2fv0iaSz9EBG9iBjQsI4WJ7d7dKMP48w\r\nF57Cx3Nr5TcSs6AHYoR5Ym5KANtJSSvGvjOi/BRsFkzYyJzxC8By52Bmk9PZ\r\nCFX1CXm+aqvXENxiV3XGxjLrodsoBJYO6bA=\r\n=1pHb\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2017ccb77ea6da871a9c6ab7424d883e382bbc2c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1652666579732_1652666664077_0.4639981129256241","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1653012197332":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1653012197332","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1653012197332","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"6caf79b475448e56129e5e66ca4b87c61d67014b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1653012197332.tgz","fileCount":8,"integrity":"sha512-QYcjqiqpTJirsD3N9BMj+zLM5sX4dKzz2FFXqEpVwfh67LyErCgv/m3oV31vCTeWFbJKX6A8JGJ9cyUoqGK7dg==","signatures":[{"sig":"MEUCIQCM8r8YqhPx1fONVqqHHvX0PbWvuxuZTbz1QBnfep3NtQIgEcnL7Bo/JulePgtbbplQR4Q5rHr0nxPZyLG977B/Juw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihvcZACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqcZw/+LGkSdTZ10EpwR9CBtXD8IWA0JFv6atJnbXOoMDxjjh9OPWpl\r\nIXmry+gKkHnBA7gkmaIcluVxprYYwRzD/li8uK3b1cwvDebrjqyGap53GbrE\r\nRamDpPffpZ0DxxPw4FOzW0a5zs+xwburkwmxT+yfQkZ/B07HaSB5GmXeU4mL\r\n5f1AKpja52MoGyk5ScHXXDx6RJpLnsa+cDki5gFBuUrK2SPY1m1caUXphftL\r\nfvRoEYcC1GGquWngTmT+TBD8koDHZwxBPz0efrOhQa9EyGSerE8IFtZFO9hi\r\n34HYfiN8ah7bKBi/7grgq/Xxqvcf/kjToEzDkg/9eq1n1r54CYQfZahzeGji\r\nvhotjXAVOXNIAqIajrc+P7y161e2h7YSt3pdz2NwFydYezN+rUkKvH4BZABq\r\ntOXAa0Z5UdesOJHBEbPt02l+6uyuah0sdf1bGo7RLqE0Y/axnkSklSGxEn1T\r\nG9W0hrTHfrBEYBtxDfZ6QfKR4nlW/U2dKdRi3JeJS3HpY3Y5NYSB/GykWLre\r\ntD5+J9y3kOE/OvJLCWAYVZFS35ckKTUvmEA7yW1iCvHCi7WQnaORNnpyOpGq\r\n1pS6NZJcLN65DzaA0OpcYAU9u5gRHt0HKuzll+TmFvKOlVD988IWLOCW5Nfz\r\nxE2t8GmE4L5dmdC+lvf8gIRs81L2/3TrznI=\r\n=aBX5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8371bccd77e3ab5f90ccddb319112f842aeffcc2","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1653012197332_1653012249489_0.6610310207270111","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1653271344220":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1653271344220","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1653271344220","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"33e49a99497197e51445fe15e7205c5f89fa291c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1653271344220.tgz","fileCount":8,"integrity":"sha512-GyxlNzWASD5+V8FC31aDj+05t82JQIVfJn2GYcJIycY5Tdbcm8srXz8m+5v905boVy0Ml8xuP9TVz3P5BIE0rg==","signatures":[{"sig":"MEQCICUkA1Bqbg8VXcmxfNvUFbhY+knq4NJt2vPh1tLKC1LPAiBAwMxwUY6nGflkwOCssz5McL/N0PBlfBTlg3TjoHw03Q==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiiutnACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoTwA/+JcndFyw/26c/4UMMv0DbTP6olAARD8HB3019MQCGfqXnjN+I\r\n4t6WLMKFnHKnoEq7smt4mkkiIWcLz7KLsRZwrge7Hc5VUVGKzyhtcyMzhWDb\r\nKcrKQWSe6qnnSO6iMwBiXkjVSFvagWk5DgpChI8/mx86/kglqow3eOHPI58N\r\nG5KG0YNKoy5GBZST3kca69a3UIkr9bORzYwogKJRRu3EGW+/JRDkkvBQlDtq\r\nVCE89TrR31tlF3q4NiIcNxvz8SjfNQ5LBpSFHYLBk2NAKcqS+oQJApDmtByj\r\nN48LHF2Qekw9FFuW0CR5Zl0iGCvFVMNO1nSWF7oSwVajvSvijOmlDRB2h9cf\r\nNn7rV38tIQAKVhobNeZHJkGZgyUM2fGzT4b3u46Q3pnv9qmSAFRL+gREJs+Y\r\ndj0Zl1yqQzBMik9UN28mK2QU6pHX7aGEUygwgWGeSOrEAm8GMdA/T8oNLQq1\r\nl3F9c36xrhbQaX7vLnxoGlnbjDr24UDw9+EXDI3R6gr4l1Mbcrna+TqhhbQv\r\nLoeFL6OX6q1672IARrHaRji95wnv/orcPmve/7YS88i6gpzhHxiHWb4BXd58\r\nc8g+i5aO4mApzVB8IwLmIfxjQRCDYV8kAnP/g4cL3G5MI2F37v0nGPLYy91j\r\nWsMc4Ul4IUk9DnoVZptzmdcVD1/rnNnOglM=\r\n=QZiA\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"b0683d880638061304c73d85fa704bdddd710ab7","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.16.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1653271344220_1653271399284_0.6998044462870334","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1653876120437":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1653876120437","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1653876120437","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"19ea5cbae7ae504a653d4aca13039d4c4538185f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1653876120437.tgz","fileCount":8,"integrity":"sha512-mGHLQ2a2nkJE2QJ7/j8Dy2jq2K20g5uxFahuEFcK7h2XOmTmd++KRIS/Aoba9/Rgfwl95FNQO2CCL1bsftIwzA==","signatures":[{"sig":"MEUCIGiQouSTmWq78+US9rgk0fIBzN/sfyklIPEyh/OJ4bMLAiEAgjEwWvAUObiqTaD0tVIlI4x1fC3JSOM+CC1nZpfTvNQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilCXGACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqDjw/+KSUX10/tzJuPg4WuSV2/Bgr/FLnF4/VKx4BtrjGVMlhCKvu0\r\nJBlE8zgxfFRlDKH1L09oh6xJtI9vOqcVLfXgCnAl0q/J4AR4+ZHDGmpZ88zJ\r\ng6ztpUrdf2+3VHbpw65ksBjHcSIMTDUgLz4bmJ/va9TnGSLwXmd6RyplYr2Z\r\ntbZWWcjaPtOhca6V+9RXzOr5sBZi5YDhLZtp3Z/xUCHsvAuuYfdLl3gf1BRo\r\n9R6mX/ge5yOF8Sg2lOlXVSA4iQBxyuU8o/4PBTdXuQc/jXHTWanF/n60Javn\r\nYH0y41K2slKvIyyHjgO0wzaQdC9TDMnTFL5dbMzhpV9BbiTDg+pfaBu+IkR5\r\nmmkxmaAWSJxd/Y2LfVDawHxZSaTNwtbOZGcJqHtVAQnYHl3Mswl/b6UvF452\r\nvAPR/3oYVdgB+dTQQ4yZ/zdwXfBkd68S5DM6g8rPPdOZzdRSF/gLaniL6kBk\r\nG9kOKuzOw4JFfHqbs6HszcL0TXpZIP5yYrt95Yq7iBIqOPSghIyA+wnDIaOt\r\neQInPu5fHShOcPZcunfN7D/9eqOXsH8qtzMlM5wPWhLR+ybRkfguUOjUemPb\r\nHYW74EB7QAhp2fWnM1IIw4hoOe01NFL7xh+8t1LpjvewFRqBc64bEAhRiv0A\r\nwMrqECZK8J9qlmMSCEklgDXSXJwoYYrwOtM=\r\n=74o5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"5d48e3ceaee491f731bb44b6bff2af5a61bc5536","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1653876120437_1653876166667_0.36204685700697326","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1653962587438":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1653962587438","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1653962587438","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7d96ee6d95d44c634aac60a8701aa17730cd99a5","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1653962587438.tgz","fileCount":8,"integrity":"sha512-pOoJdXmPYF0K3tC5vz0TB27fjIxqHgHhCUFnwA5PT5i358+WUn/dsr+IDInojzZUlnbVqRd2Ic8JnXsemN+nlg==","signatures":[{"sig":"MEUCIBNqoEHHza4DtE9HvniOyFzjknpnU33dmZjr63vjOB3CAiEA9omP1wYsvmL/fHVL6G0u9wMJrprTxOaKPuVkGVpKkVI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilXeTACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr+hw/+N9cjdgWEJO+/QO41MenAqBNlhhDRsfr1d7jZb9toGu5NkXUt\r\nSIR/C/tNCTrGrSp3M7D/Zu+9CejuP6yNWAjSMhCrlS2LRUv7k11F6BVV9GxA\r\n5S976HuZKbSsRSSANPbn1Knmm8OvvcTX/PxMQVkWrIKiKxkkIZmXHbgMI6v8\r\nAg4r9gOyMq2YjT8C7A6USxavLjt+gzE8d6CXuggWxk2uI6EgHe22gK4/NnPg\r\nnrJFaSIwpKxcn9rJCmdutF6NSr/PmRRY3+7cfc3NEGvnl8mxssAykETQhtrk\r\nDTe7kJt/uUfKluxi28P0GOKyOz4ul9mBu7JKfJejQAOPxw7mSRurJ6jfLQd2\r\nWYFl2gvnPVtCHq6BBzXsv9wkgmVBshfcpGpZ4Yb+JTWIbH2pVONfr5j4TdCw\r\np7vXF56JgRNDgiaxnXOFyqA3HBV/mYxs/cPdrkG2grimM243SJEtKA7yFfml\r\noODhNCA1wQsC4C5a2rX+13jD5vxgf8pmtOk9uK+B5lmLDlgGdqV9uQknpEI3\r\nOPEMc3+qyjCbqYvv9DZ4DBMg2LtCpw6KEQ7Y3JFxPrvPMaGT2iZWZK+auVfQ\r\nJhpeVyHpbwR6LUw1q7WJAKFYh5su/F+TfPxPZrV+4uskRfsEoXytntzm/1JT\r\nGXZ3wLcdN1Me1oCH05rwFbC3TL21YrgvbCM=\r\n=kEBC\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"d5d4e0d08e4c3a52fbd4f408f607ba446a2d507c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.16","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1653962587438_1653962642795_0.6624020535000417","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1654049397500":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1654049397500","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1654049397500","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f01cc45244123fffe9a40ea51fe63df45cacd24c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1654049397500.tgz","fileCount":8,"integrity":"sha512-ImDrIdV6h2qZvlBYsEdYE8VNTy5yULB7tTfXbw0l1M2E7UUPW7V/Rs7pQ0RE1nXExrj9rpRzU2/VWPeXeJpQqQ==","signatures":[{"sig":"MEUCIQCBRauTomFLGeAe2+g5ozEdn6Z/THKZfEiNgAXAr4FBJAIgOHTYa5pfb38dVQIwjTAF25nDTs3s1YHKYSBU2pMOdnM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilsqkACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq3lA/+Lw5u3guYNxi6Ri04XZkGQag2Qc7kIlBqnPaU6+uA6rltQfGw\r\nQ1VCRiT4NyJ/pmAEQVbmOWEp8q8yHXowlTd9U/8Q8DFoCe3wh6411dAJCW4i\r\n0mJouwrlvwO8wkbtXeU9v+/EYdmZF8+AmVb2+n3RveWunFwBK9D44b0FdkVJ\r\nafjsJ/ntAi9s56Fzgn8r6xNlVg6t4ZnI1KKJL5bDSom5YkRE34KmGBgUq+tP\r\nM2tP+u/nV6YbgZsZXonOosfvcIpsiWCYBa4wy1t0et+rjZ50wPF3ESAfs7Fw\r\nFMZv8qShaZtpxnJjWvtfhNtViNFpB9pjqGzYSFpXGfMNQ/xPv1A8LyEd8maA\r\npq3vMvxtSUSowVi+ReR1KTe/s5AFJOSCrarKFISyVKXsXs6pQx+zHiNCuajK\r\nvLP7Otf5Q0HvTz8ojKrvaRhrpH3Gd1mtJfdYfIvlVb6n91X6gEWDGm3ZBjdU\r\nrMSiCkBerESVeWkqAnV/Ltchy3ntIpd3cL8eXbh3NR3KbfNfmwCQw6mSqN0x\r\nBTTLgMdxhMqTFFZ7dCA6W18qNXv57edIdX3Olox+mGj3SG1+KOo44dTkFqow\r\nktH0ZznnsW+vQY+JusxvESh3NsXB5rzcGFddWOavU6GFlse9jzLfPlKorIT1\r\nucxMGjFG4vrd7AHDF5Ak9Zq3qfxAQPvbB6Q=\r\n=pN9e\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"d3dd8847cad47e408d6d7c756abac4012329c0c7","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1654049397500_1654049444485_0.6189557665419423","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1654135408243":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1654135408243","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1654135408243","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7037762bc84e460e195db3577d6f31dee590b3bc","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1654135408243.tgz","fileCount":8,"integrity":"sha512-2Zm58fbAVly1dGaO56269vTz9ae1GmB5NcBgm5hItfHgKRw59XD2xUG+xXqGYAhqMp7smbWSyMRYNp5Aqoj9bg==","signatures":[{"sig":"MEUCIG4bn0N8HxHYpxxdJw/6oVSBg9to5HgmnBs/0lYZ2cquAiEAvLHcAg+AYIGWUXOUnwfSad/9gM0Z8HLSHmQmc0FlQlw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimBqjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpZAA//UD5WNMG2Ug6JhNo4XgT5wNG15vCdmBjShuNAkLRaXuUZXJpM\r\ntvnaJY1FMnGLrBlgUl/RUZaSvZDN5Iq6GlQzd6DxigRNAH6JLgUb2TtTGZ1c\r\n189qV6UFDcOVgB8SHr9cpNXSTL67/J03eT8M46eKhLDnWHOFqFIg+dPOLbSF\r\nmNodFMyWU/pj2y5FmAQ8nKt6pynh2AUxKWs5f0cvbUH3yM+WzETrwIpW2DaJ\r\nsrmVMFUNy+4gsFHG5+vVdfUZE7CrPaZUv2aDjukBNClfz4t++HD73/1YjqkA\r\nzGW3uNEP6irQ/2meeV1B26mBPvfcGFZXqv4gHb+iYrFXdLfEwkSFaPhu52Tw\r\njSs5jQ0k+QFFb5ooMZNFFonWXvTT4jtIc6keX/WY4WyVwVX+9cGHSwIAi+r2\r\nCy2J4Oh86Hk+gEuFFuMeOAZuh7Caan0wetjKsTof/vCx4w7trH48tD9sPMaY\r\n2dw91NyfO/mmhPG60C8/lbn3dDud5uWa6jqsDnTsaFyhmgDDBllFx/RcEKbA\r\nRmHe1GEd5KnxAP3rCcAyjm4OnHGANCsEKUm2NqgYHrrZL8NJoH0GzJ+gFzNn\r\nqimRTU0TYhfY4MLZ0o1cVwyAoABPCMFQ7e0ZYIyT80E09lm5c+hoUnqnmt09\r\nZGscjeIyPFtS8ALrlpSPAwsBs1kb3Tm8FIM=\r\n=ZytM\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"1f6f6788cf56e800365a29413fad1443ead88102","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1654135408243_1654135458921_0.5380662205603315","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1654135427904":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1654135427904","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1654135427904","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"17961e603dbd94a4366f4d1e3db9d98089a211eb","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1654135427904.tgz","fileCount":8,"integrity":"sha512-aWsSBvLVv6Djs6CRvAfpgFg8qY/gkR1jg8LzzUKOVf0+wEYlmd0i7ztThlXqL+A8i/Zj9dqQWmK1tAaUZuRDJA==","signatures":[{"sig":"MEQCICxDgMQilrU2btnrEQhxGpm4bJL5Tl+HEAcGv0l3kgcPAiBBCGkTAeZdgHcJvH1nXK/3LDbulJY7borZzqMWw5iavg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimBq0ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpblxAAgsOEqBNg2VvBM9+1V5dt+kbgLHxhUipOC484KdSt274U3uvZ\r\n14gMnLqqz+W7HArOiOdEHeuLYOGNJiBi5gLXO0R8SpklWsahQq6qhDzODsIE\r\nPVSRsvWA5TkNcmmutWwCsAEe34wDSTRoLJKe9D5zF08tN/bY6xa0BjH/gC+P\r\nXgIhcDtBkIHhWc89MhYkz+KXL9m0uJSWMu6jqb7kbs/S+tliziq/BoD8NBkj\r\nWncxKrijGHTnzPQE2LNSBipU4/SAWpkH+wU96+1/CqeHtbakEf9uE4aoxJ2d\r\nZRWUaTsoFVB2FLlCDk5dHAhTLVhOg76BZX6Y5OmWO6pqMFuFyRDm0/TlDErX\r\n2egdnAVbf569a72KqtMbtwXLGjH8kRcLAbF2aOpF+9zg2/gglFzmMbAHBnlm\r\n3cQTqbRzMTF8xWzLLP2yM+p7403IpPJ0Ys6xH0sY2t+ro6O0E85SIpXIsItV\r\nCk8w1zDchCPNJL9SaNjBJI6I/AjfpU3YJPTwYJNnOAbqBdbXbTNW72I0u68A\r\nuoefC11wWc3UpvlaDAMCrbfhu5SiFOcyiCDvuyjyTGFoDNgYP/tqoNZro3FB\r\nXzNlNTptWgd7RZpgEQyXKIXM5so+sY7T1lTxJh0dph3jiwO1Pt2AfVmZ4ogL\r\nL152+iNboPlGVTLfwy1+TegsminrwXq8c+g=\r\n=dm6U\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"72b661fbcf27e8ad4f28152bec9a76e241ccd45d","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.22.17","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1654135427904_1654135476743_0.6414536550995389","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1654481051315":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1654481051315","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1654481051315","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"7a2501eaec6dc6a1ec1acc6bbbd828fcbe4c7c10","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1654481051315.tgz","fileCount":8,"integrity":"sha512-r5AMP4BkAaP/kAKlKLo6B9xafzwYVCe6ynPj13FnNQbFiJuPGkEV+heNU9p1B6O+d2unRIyTln+lRdGZ/ckAjg==","signatures":[{"sig":"MEYCIQDzrs/UWNBsR2I6gQABCWBM7F6jXBlvEORH8UFMpAQ50QIhALWXWKv1xZDquvnVeH5tdQMGmpkwKd2P04ksOalJfVrz","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJinWDOACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpBQA//eKhZEPt77JfySP8nm7QOQHlQCO8iUku00z/jyg3savsBCLJZ\r\nNieo1qtpPzARfXNoz/LIiSA9rv85jKqU/KeIaoTzgbY/DQrqL8xceCuvvUdX\r\njTTBmDGIO9AwLG0HrJ5Pblm+GDecx1ZRaAnTCs88ytHw7BNkIn6h8kwDXcDO\r\nXIbnA9LZaUFK4ecJWhbHlKsIzCDYCq/EdDzNznDQ2fma/txUMRZKEqL96jVm\r\nbJ0Rq+NBbNc6S/i5Zm4YIp6fuV6BBRZTpIvF9PLCyxaRE+5vv7ZDLGzzZa5c\r\nuuNAF7Tf+GehGRYobEDqNfxu6a50o+m1XIcd/kQpXCaPH7K/Mws1meL/Owjt\r\nDRXbWhI33J7TVwTrWwGM1cp5MinyYpZL0wWJ4UbA6pD396SGlnBFr1hBZypP\r\nBM+oHFcBf9KCPQt3TEagtIz7Jn4MVKqnceB1KfSSh+HTMNsQKbFgb9zhqaxa\r\nfAYulXOxbifzMpSRSOnKlQALBVp665458L1v2U8CB6CbSRJ8Gg/72G4usVjH\r\nx2UZvvZcteqs2l6lz9s3pEkUcxuic1DNXHZ0N+73EbvPVt19l1RcY447+OJx\r\nxG38121W1oQxs5Wj+CEu/N+HZRCtWkpSKtPEDjcqDolkZbLTPUFXxmLLDqGM\r\nENFzaLo8q3eoMUflz5oDFqjOuWH6fRHTMmo=\r\n=llnD\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"10d655489552bf0873022165c0c8585d7d9b8e8e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.17.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1654481051315_1654481102708_0.02128972915064864","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1654653730041":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1654653730041","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1654653730041","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"245dae75e9e6906ea2f13e4319200132a5259091","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1654653730041.tgz","fileCount":8,"integrity":"sha512-nNfOKlfKWP5SkqSZt3Tz/ERKHrbKtwddfLh1cWiMRVoRTwZSN6T2G14vtXyU/TGPvRw41l+11pPNbIhrySzVaw==","signatures":[{"sig":"MEUCIBLqBySIxAkP/8c3FCnkWuuCm17tTfWyF+yWWbhyOVopAiEAjz65XcgTD4CU4r/78PBQacMd5TCsLZVJpVB0akX7e64=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJioANcACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp+Uw//SZfcqXBPO2+V7oPDs/ax4FE0ycz7HRoZ9gs45vAXygalIgx/\r\nDwxTWRDv/DMIa7jbBA0fehqFzttmkv5WnzUzERtqyWT8a/kZDEpt/qT5xJB3\r\nt/J1Gda+fQRmu7hfCUDY9fZLbXCncLVcE+DpmuBpWNFdpM7gFj9wBK+91vuD\r\nU3YCOO6S/KDmGpQysRW7PuQr5MbIDipAGn9UtHi9ES2NYAQtov54/nb3TUcg\r\nGBsfyr0E/nq8tWCunb+rUDbEGyqFc+uiyuz7DmzYw5qa/GsUP0zpb73u6pt2\r\nRj3kF1fYTdtzAlGUg8k2UZTnfrVy9og2qFl0n4K3ePjdomtKtUZz2SJHQX8x\r\n2oT+0Mxdu5gNnCnBuy0wI6Sen1P63FqxFSP212MDc4SR3nqsXymZyqo7ir+i\r\nfsl8kHP7E59kRiExJ79Y87oX8upQuE7bdx0W2/a0+S7Peu9og4OVLtwKQ4BG\r\nMQR2+XrtUp238AvF9ssmKX1mjpZPIJppeLWp9T9bgIwu44zNpZAJqLeD1hsf\r\ngCv7w7eZZ0npf/URfE9G6lVK/UMErW6gy6OGEvuydOOKlH4+8/Xsfv4G/hPv\r\nsNTFa3Z45OCrLWPC5uLNCBvvwrgNQcjZBBNpETOfxZy9Ik8ZWQTuKI++l7nC\r\n4/fUHH7a4L4ECP9wQaAVmdUiFVzBxmWCn30=\r\n=Z4eq\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8c1a1ed12f808cad082171fa40f6b3aae284f6b9","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1654653730041_1654653788573_0.38994529461879446","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1655690661708":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1655690661708","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1655690661708","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"293ac1bec19e0355c52b5077c964a96e59cfa099","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1655690661708.tgz","fileCount":8,"integrity":"sha512-5bCC+KHFROZ2eeyMakVWVG0S9DaTiFKecI0jbWfM/5e3Q+HMhnehJLm9i6eZkXHTWRWmyG+6FzZghMxdDBI17A==","signatures":[{"sig":"MEUCIQCdGutNdI8srzqXGWKKiexZoD+PUWOCzmOR5QPT2kLtawIgLNjUvIgh0UC1/QbeJZBuilFKCU22Fm00J2gQnC4BInI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJir9XTACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrVxQ//b6/8cOp3cxXtcLHX/G9CLwRWoWqn1Cx9Cd6hGrw+9CpTegf0\r\nUQBZB5XMZG0Uv5TiZ8pzLsAmzswPfO4r7Q/rZDLwVykhUFx6m+5wG9v0W+Eb\r\nukM8L1lA5mSEZchEdnfOXmZOf9BJEu+yxOeGHLhgQR7uzXUNJDoQrEyG+GG6\r\nAWxYj0fvmnVtJDU+Tyi+f+2k6cK+/OS8x/L1d9JQIcUwavRpcqa3s53GFIDE\r\nBu8VEy/e2H9wCIjxdGz1WKKNY1IGY1w8vUl80rkDl3uxPJoIONIN+ePlEKZR\r\nDQbZZAFYAbDUH00E9jlMjq5i9OUBzzh7Q7ynDKToEkUbMQyk15BPyjofA4Mf\r\nUHRfZ996MP5RGLh51YWLXfxNLdh7bp27G8yFm7MgSUsqJVyEP5EcwV5oMCAm\r\nFU1WGNIat4f7RF1uykdKiGqf/VDZcxzwsH6uajhetdNnWSFpunxp1ripUUnh\r\nz3QZoaNi1ewHbDWhfHjYMT5hcwPonKHvE+DGCdcfrMdwT0srZq/OQAzH7flb\r\nUKIzcbLzsD2qy/B+P0X9dYQ2VXi1Jow32jbMQnxW7qvU1k5gNCcaxrjU5C1A\r\nQHhADjQhUDhU1D1C9K2uNt/hE/KMoXoAnMgNV5EYwJ7kFc1UZId5d/ojfaca\r\nIu08T934q8tHuerDt/0sLXTZw1FwS/B5Wdo=\r\n=w3Rx\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"213ec23feaafdf2819516dc37da87ba68be540f9","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.18.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1655690661708_1655690707011_0.3030136477345795","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1655777284220":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1655777284220","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1655777284220","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"5985d313cac661a6feb5ee057fb734293436706c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1655777284220.tgz","fileCount":8,"integrity":"sha512-ic5JqN7nSvJFQBYM+wm2dPtppA2loZvH8FUP6T5U3DunDo9qSgBXAf5fyZOe6j6rnnvvzpfu6Ft8Je6aT9knUw==","signatures":[{"sig":"MEUCIBJOsVIulZr8jt0N4j936BtsaVhNMmDnOTRC4xB6R/CHAiEArjn+Yt9r/NrywufIZ9spCHn2IqpCxg2bWJlF/GVMAa8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJisSg2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpscQ//RfLszsYRoQqYCO4FZYxWK0o1P9OOaShjpGVu/IQV1F9fiPBi\r\nk3MRZ4TwQSMHTYxUAuK0uQebIqZG+Nee2XSICMOELYYF/N6uBlynnzGo945m\r\nHExLJn16PF7Ereu+PsazLSVyQYIQLyNwvX1hEoRMr9OTk/erCVvbG3lAyeh4\r\nZcpt/hOwV/srEUMC7cwBZ8IwoS5nKszrjP318B7rDBrJTF95fiFob6CvM22B\r\nMKG7jDM6A+xlnFNIU4nzopJMMW7cpjkR28fkWoh6yOgMnyxl+40PjZkQ1uhH\r\n19LBVtqVyWa8fkvfcevuE4TBQHb569rqfCABPlCawTYHc0JUL9kXcpZF6KHU\r\nVe8Jh+WiBYrOs7LWQBs+CXPip7yCVZU0dbIHEbq5anw6IUSGX9r65D3TZKVf\r\ntdixKdMiMKmLHyQowf9sXnLH1LXRBZM54Z2AsovFEer5oaXqilY5CYOWQ6cu\r\ncELy402PaT62PcR2TadlqXrCkC8ZiLhN00pcgbEEAE8tPMXAO1Gb8TLS1fR2\r\nVnybzu6IRo9wY6NUdbiLB52oK/NGSHLls7/WfdyYFeBsNUxORiyvkFXYufAb\r\nzF1D1MFOrkjH7A7cWVQvtYPgdRwlUnkJlyx1B43CW9n6kpwB0vkX3CG2AjqI\r\nEK6jaXR4r9SH1tL68AnFrESx3KpN+ScCcPY=\r\n=USom\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"50b6917449f4af0d72fa212e02b049f158307f94","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1655777284220_1655777333971_0.0627526872532671","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1656064386298":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1656064386298","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1656064386298","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b623fdf0747b4b983dd2c4de9fbd60d8bae93847","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1656064386298.tgz","fileCount":8,"integrity":"sha512-F66WV32H0ekTLVSN7K4nlVM3T03ZIcH1VDJvgFNbo4/43/2aftaz/spp4LoZARO3Y4zUhwISNl0yleXUMzp1zw==","signatures":[{"sig":"MEUCIQCpDOKMXe1ehXRubyaVmaR7sDLsXbx2EqIIUQltENUPEgIgIL/DF9YRRyzSOxUuaVgWCDey0kfBO8xuIzMI/ZR5MmY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJitYm+ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqp7Q/+LyT1NQh9zyJ8y2yVfroEVyna0RiW9+mPOLOzpQJU6CbtIByy\r\nSVJCEFucYl185HS4kbg2pwh2PLGUYONs0NKvun1CcJEXGraqLnM8rrBMAMIp\r\nW76qhqpZF7R77GM76VvxQw2cCI2Hzr6VpAccuwl7PsOCl9c0qrqfZRF4Gqr9\r\n689IKamJPYO4fL4B4pzgzJkyr0vHbk8dWFt3EKsEM3/WYqR3FhvtxMgzmSx0\r\nMZkJmlvi3XE4wCtZi8+kteDkXqPJCP1oDp2O4Hn47tGU4CMYSWz4SRs4hMLF\r\nCGTh+5gvjzjxb311i5FxkqtmVrgnv1aHE5oUphwN00TW1a/nT9FFi7rHX/2Z\r\n5zD4FjIDJ7Pc169N8wDNFnQy5S39K2MvSgg06wyiz69FvLUS9dRnX88q6a/D\r\nfFFsTTeVptAY11O4+StkxkvqctzZ7e2Bnc2aAwn/qi5eoqbKeqk8TpIUCAPR\r\n47WfVDylK9tvj7c6OBQIRJ3rSmnNBVrDFDyfltW3ERf/PTibze/sLJ6dZ0or\r\n1/u6YWpJ/0HVv9Dk8qGc51cgXogN3PLSZV+ZcfeF08ZsH5HzPG/Yg/rTxr/6\r\nQcyYbihJP30SZgm88Wcx00hsJIZizAQQsrfP3GUCBhcVA3KP9L6tMt/Kmny3\r\ndMzH+gZSYOrFfhz/toTAmoC00jmULHNEIos=\r\n=oorN\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"718f78dabbca081342c7ba6128ac3998387d82db","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1656064386298_1656064446270_0.6923639745028425","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1656296141566":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1656296141566","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1656296141566","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f456b52c93262b99015235e52c48560856912b00","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1656296141566.tgz","fileCount":8,"integrity":"sha512-0dCts16MeuaDP9cN9MnDQ66tAjPa4/E+NhYFQ7Clh/SF80YhsR5hrFEqANShiifc/q4M6ges/IZ+lDvDtGCjSg==","signatures":[{"sig":"MEUCIFEPk6jNNPeqv3Ai43zmTIM2FU8HDXDtoTxaAENC9sHzAiEA+bMd2LC79B+Kp32UFlDIPJ+BqWaXJH+G9aBeNx50cFQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiuRMCACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpeOxAAhATBBJG6Czq9eWn+gaktRQNQ6aXWitwxm1+TENJEByUcD1nM\r\nBsqgovEpDwKohsaFlbr1LU6qpPqc7Bp0OcxKlfF19Is2FxgPWxX1OAUSePR4\r\ntCkCZtvabjPb03d2l7k8mSHFAJhJCaBoqu67UesmTlYtz3S3sReMkohHZM5e\r\nNbhTft7sc4FZ6KOXQ8q2k/AuG3in5aVwNsJYK46S/GGN/3GAZAExoHzMHzDy\r\ncHXLJW/6MdlqJ48xKvOk9kIcP0rQ3VZJ5bxAukIdhJM+hnfuTBJ9DJx894bV\r\nyyM3bzWaVZw8eGn6HutxvtpGYRLIlp4B7g3al9m8F5+qbWT0s3cOW1FwYEdZ\r\nNxT4Pr6g/UQhqBhK4GYhMhZ3UoDhMUe6CQd4hfcMK9Qthvt+lU/RugWZDYcz\r\nq1pNMwPSJlTmDa96Ou1jnvwjb2sp02x1BwlA6W/08dX08XCHJ8l5Ry9jM1BD\r\nWOWuyJ2ogYuPZrWGcyuVYr05gwBZ1TdHdfiF0BLD3+ZAGt9qxSw9skffVp6T\r\nVclA49Dls8y2Q7ZPQcy3uKSrAhARfTAGacAK00rLnT4/bWsA8aCuZ0puFSu5\r\n+1fOwaFLNiOu9pnm5ZgkogLhzo/sE+62G5bb/8YWxy9A/cK/1UeAQ16/T5BE\r\nv+yb6fZh2TyJktCNOmtoayZczP274Pymfgw=\r\n=VKCo\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"d8ceceb763d60bfd8c8bb74444dd7384add65c13","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^22.0.1","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1656296141566_1656296194017_0.9066064797763125","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1656296250510":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1656296250510","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1656296250510","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"104f69505b294d2d073d3fd914e7cbc3d1642116","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1656296250510.tgz","fileCount":8,"integrity":"sha512-eluQ4kjh6+QWYQvF9+7CJBRdF2K0XU42gI1xgWX3dx4ZzDz+585VBJHhKfomW13bP6+ztudL0UzFTzgQ6DcyXw==","signatures":[{"sig":"MEUCIQDA1hsucRbZVnkhFB02ssnuhdeh55e1g5IcY0b7zqbZngIgMOxEHD2n0bZyvoohb3lhxd+iCZDsXuTt0Pl8AluOTfA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiuRNtACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpcBw/9Hk0hihRPrIbcCeQDl8/jLLNDFBpzfZ82nfh/A2oglrvhI1Gf\r\nkThz6ACN2d71grUXXfzAChmE0AFwthYalV9XH8YH9P8LpirFODEPuPXur5g2\r\ntu9grkxSzH86ZacSi2U0d9Z194JUYePnqftFyvDHyX3fpNc2ovspooA3urYL\r\nIirCwffQCAToCGSA94F1oO7lDykZIQh8ODJ7d3lY5bx1f6yt68ytBMg+L2B4\r\nHalHXghlN1lWkUnwL6a8Wf07RwGdm9l8LRmRlT/8aBlGekQUnmpCKr1LLSI9\r\nkiI1vxpviB1Tpa2XE9O8+WgxCStNF+b94Beb/KGwUjFZVDOWshA2WCYyFVjt\r\nNGTczj/B6Ctm4xxato5vU+eTZKCBt1Z1fzgWZfqSqRlZNhwedcyxhWA7yzIw\r\nB7hDSiody7JHCGAGZF2MXNq4zxpJRkWlRrEVaI5VlQVdP/gf8DjoQUqSxtnp\r\ncai8C+mByTRo/IM2pn1+2Z9Eqhw0DL//wJIU5nFCaTpwSn28x9rhYoTkQ+Qq\r\nNLUO2G0sJhZW1c6EdLUYaeOEkyA1n3Om5HO/iU+GHPcPFrSLAaTXoAYCiI2O\r\nMuTlyogW6P+wLp0foWyoI4+lelUauLIulV+vUgqrPWQDLucbYjLTfE+rJ7xm\r\ncv/kY3zLEn7Yl/ftu5JJO8dU54SFXim1dno=\r\n=1Aet\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"e562b6e531b9dbb0b086e9888dbe980d1024ddd3","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.1","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1656296250510_1656296301709_0.4455763113798936","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1656381846589":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1656381846589","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1656381846589","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"cd5299933f7ff2e299a8a6954280005bc47a5951","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1656381846589.tgz","fileCount":8,"integrity":"sha512-Mfu69j2bHo4UDcQz4VCsAYEffYz0vOefU5kHaq19PJ7+7prbVTdfaDD6GZtMydJv3t3TzdWJfEoTJGHPuL9urA==","signatures":[{"sig":"MEUCIQD1ExZTJSrZMY4m1OFnKiz0RC6IEg7NTQUTZwCGVVddMAIgVpYFZOje+f+gYzxHU/Hbq/AEE32xwFJusRFdotH3XWE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiumHJACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpZvw/8C4BoJaxk8JPWC0QE4uWI3Z9h23FPwaajd268alXCa2MRMQc5\r\n9JOIQhohocHAiL0xEMud8I1QPmm2QU34lulgE+ziTV/JXjcsy4GJ69FpC0gz\r\ndDvIPYlu3cnQzYMIyE1QCxl1Vk2E1Q7t+1wC9lAxliQAqR2dMeZr4swWoW8C\r\nni2kMJejBM3j4WTYtE0B0szA3bk4qdv6Jyujd6qd8mbAVYTiKQVHVatvertf\r\nyugItsNH5mw7frrOKLtOmTlf7KaVtm2+kZUfPbCzur7oxUMPe6cKXh+V9TQI\r\nEw5kHgAgNRjOl5kV9uA8r55rcRPW6+FhiBd6GfLa7tmNagmVynlSXfXa0Lj4\r\nEKVokbtEOYKr/p4TcadF1TY5GtaB5WvAfi0w4QAAo+8T4b9e/5Z+7QX+Vajo\r\nbPU/AN0gTbnmg67oImQmhA8zjtnnDtfSnoASQiJJxfNLmOMEIcadNdik+Fcn\r\nm6Q0r5LvwWlnu92nX9CFpyx2G3BhWRFz16iYPnfLZsBe1TEmc+oYTmeaZHaO\r\nkIciOYmyW6qZjEBwI6q4BpsM3MjQF9bEx8B20S9EUfQN23nGfHqOm2gtKUeP\r\n9Lu8dr+/wUq+lZW69bKbksWGTZ9FFNUlHyqkGfB3WQKbTs1MqaPD11n37NF6\r\nGHKESctTq0wz3M4tDOcAvcLa/wJFDRQrCEU=\r\n=S1GN\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"50a3dc66de3779d6b57f3661d902b1ad6c71b350","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.2","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1656381846589_1656381897682_0.7628032911749467","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1656900179721":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1656900179721","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1656900179721","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ce9dbc26b636241589f2c284ca1ec33e1b70e2aa","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1656900179721.tgz","fileCount":8,"integrity":"sha512-D1Dfx2d8/tWQLrGn9dgxQPR2E/apVEAT4s5+gCGUWhL7bNIqvtzvyCh1+6wAFwCXJNRc8zJdHKNuGVCptM/daQ==","signatures":[{"sig":"MEQCIB0jJqRQydnuwg4/N4L+AupiXwI1EG8rc7I0xANaCHDrAiBqhmgfjEOOUbWZEn1maVplFDoIVG8ijssMWatuocLHTw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiwkqKACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpVXRAAj8qV/d1e2tQZR0V73jK1KVTUd4QCqzWNK8bXz8Xaa6VJbisI\r\nTrn/VD6gmsgS3KOPiTAHwlhNOrTln1f2QA2HCHvN0hbDsPdKo6gtBeCfTx9R\r\nTBRZ58/Tt2rk2qbawrOghdBls5KKEy3QO6QenI415HHc6Iy2uNcf/kquIO+z\r\na0d6Xus2lEcJM0rqpRVKwy7zZ7q/5L6MojYBkqVJusDPepS6jzelJDHFoXIh\r\nIuxZfjfyqgv0rK8+2YAAfjj6NVP7x+yoqxtsq4E0jjbbbL3Iq5+0DYzz/R9x\r\nazQ56a8PRyeNEs8EoLWFXjOXlswX59eaXgSwz79f+NUfUmJnUE6OpS/FpFQ2\r\nuQCydy7XV+xiLcoL+edNunu4ZoVs5Q0yrMkA7vLMnT6awiaihqXBb6NE+4Jc\r\nPoyuRFX9cz7x7FYDRIl77h3ZpLNc7ZcHVu/ZoakJp4fWm2AlguVs2VG9cYC6\r\nc41cQHS0L7+7AOVPhWGlYgiP+SLdeHol3eRAR8N6azDFQZ9L3D9nqOoCJZ9I\r\nJYQ9bDdmfnSGXp+peMYAGpnQ79ct14sq3FUM1my08PZUU3w+K7HAT3HobywS\r\ns7fMgB8baaqbsDkxWYnlUEBwS0Xv9gQwVZSUADOVdZngSH3bBAZPACXLFW6x\r\nPMWfLDNqbslYOLgs00S7Z0fL1H2J4UaiVxs=\r\n=/Ocv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4c460b402ea3fa994e277d99d853eb28ecffe686","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.5","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1656900179721_1656900234459_0.7457379466551024","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1656900277399":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1656900277399","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1656900277399","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a9bbbaf74f21016b8ab5fef6487e7dd5cd4b07cd","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1656900277399.tgz","fileCount":8,"integrity":"sha512-+rPgeexOmetA3x8Ij8c6BCw+7X8WH/C+A6vQatYdCGC5WEcPApOUnaa50K7f0IgcqByIiNWqcWJIZV8+SLt/1A==","signatures":[{"sig":"MEQCIGDdVD5gpkC/loIGoII6ju7PYlo6L0+v8d2NY/8CILgOAiBbOdgXcckigo8+ZaaZnyIPjPq/MlCIVFJ+ifV2qhV6WQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiwkrnACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrnGA//QJ9lFbSJwt67E+OrjRNq+W427NuijiLqCCNp5/x8VUvPThlU\r\nQwSWoV7mqs9Ln/VydS5/KHhiVX7TODdlnvMJsXarjAgx5LujNuVibB+hZQsd\r\n7/19eIVxKk+pgIwGYMCIaHyYe+YTpes1AUyvKX5df9AcXzclAZRM7tUiL+Pa\r\nG4RbSiJdXWoJHN11QTHcPXQB9g3yZNbKLeYzzOZPs4JN+4/kSIQXevouQR5+\r\nGQJXH/b5nWCqnziDhewKYVFYOh55YP/bmMgpf6gTYsMggqHWNSJCCeXPe0tp\r\nOh7tALU5yQBHwintiwFteCrSOhWkyUGEEfNXBOq45fDH/x/6v1vddb2K8tqL\r\nnCCHCjXW9V3DgY4ng2kC/36l6YTlyeEWzS5uuYEHnJQsekxQ2wYNz6XMwa38\r\nciFfJHfoPwl+xSLXC08xyhSSOEl2jgShTA7CrMy+H12dQWDP+UhmtjIeatin\r\na/AlxzhCxN5F8khM/uh6rtRQAlwswfTVtsRh8SIp+rxQyqEVJQz75+L4xSVo\r\nI9NCEYgtCjm1MXY80lYjCPX3/3J66H4PEc4VpWRvAjDmHwx2pSvHMK7M0gnD\r\nDvVtocWhVTLuu4f2lrtRBMIJ70Ff5b+IXhQ/uqKI77yhKgbpYqUCY7HJEZN+\r\nZYq9VrZdU3HtrUAgLqdXUpLGj3gFk/PG3gk=\r\n=UQWr\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"594abe29d0e3765bb5940d566ae6669ed9266482","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.19.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1656900277399_1656900326956_0.1337859969720554","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1657245815754":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1657245815754","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1657245815754","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"166b0ca92d7915f1259eece7e1ddfabd7c2bd811","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1657245815754.tgz","fileCount":8,"integrity":"sha512-bsod7cgkJJTJ/BYYx04jnQVYw0BlomlsW0ewsR9PjqPid5vYZHZRaxPUALWHHVex3UKsVuEIAxwRhwQhR6mmjA==","signatures":[{"sig":"MEYCIQD362umBl0+NBz1ce1of3u9xWYTyIR+AQxecUG9iZW9XQIhALywHMZGaUoa+3sm+SXgCmcC7/tR02p+eEjxv+M58D5H","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJix5C3ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpPmA//bWCAk27okn2009RI9vVsfYZxAvjKVPSZYSbzHNyD7U3mfnms\r\no/BTXWV5mNnyTLnWjS+MG3A7P+AsvlLl3AJ8U5XwqHOlK8sSK7x++aMNW53s\r\nJqy1kwGvD+FeGn3OHz/n1WYYoKJa5TrHQFjH8wCpGofEphL8MTxrDXA+ZS7m\r\nKWyVCf1DDJleUi66KcQ1PjB2XCIcSb13fBnXekslRH95+dzuUywci9iyb/XH\r\n/3NkNl71Rx6vtmbHYc25s35fNT6NyPTzzG22S4/6FYFESjEiWSfg3toagRHo\r\noaxuSq8dhnq3BW+V4tQ+ki3Lw5T8HIKKU0L3n/mMHJ6MweBI0NB239yj2yk/\r\niCnEY4WLQiKKCWfbzCRmFDRAzoOx3SIK+rSRiXR4mgcr4qctR2vku8Q1Tcqh\r\nE+6+woJU0qIH2sqWEp3s/jS6KPkox7+c0vwxHpQSpCpoCjsT+ld2Z0aYetEy\r\n4r4sR6rU+hZxtz8g2HuTArKewBOssIj+gLuqME+U5ZBYjGZRmM7mBBukWmUU\r\nfB6kkzpFmsuCpAkbNlcwgHQZlAiJlEnPBV8if/GAXZPGUzNwpWRZgLeTgeGQ\r\nMM0quf/W8zwQChWurO31eoQZgRfn5DfLRr27ylzOt174SgoqxZ5OJxIHaDtg\r\nid/85MbkUPCWaAjhKHG4j7LZh/0wCaCwUjw=\r\n=Wyq/\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0aaf31aa288f76bacd4780e2ffb40bd305c3f655","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.6","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1657245815754_1657245879595_0.9146371711468739","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1657505351465":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1657505351465","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1657505351465","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"331c01e28c2873bd2315c7f6f15e40604ea48086","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1657505351465.tgz","fileCount":8,"integrity":"sha512-GlK+2KV2NY6bu2vUKsbQxHCKbYnbudehB43O/ANfm03fHR+3GL+US0x5kzWpaqOsDtYXnseZTqBHuk8vbF/TfA==","signatures":[{"sig":"MEUCIQC3EJVXOg4JSe68GRwcinldvgmQhNl/PlLXXpyOZEEEMAIgbPYnlrJnWgAKGVUUwPe5Y/pdrQDi0SLRcG5ke6DHbSI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiy4Z1ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoo2xAAhuUKnCPttjBFJ6mPuurJ88bWMhBJw5MS8tqsSRPqptoCx5to\r\nU3veIjQPO25VrZEuSgs/EvF9K2hUOdqVAq0mnPteTVIqb8UPnGKjaf8DDoWb\r\n03LNBG5u01NS5p69iCxm44Fb/KfwtwgOxNI1tWlapeykZ/zWp/DlZphlEtt8\r\nhJ4TEZvRPA1tpWMt+3Vs/2Xqovtm/pX9wPYqeU+M5v3JZP5K2TCn7sCsrEkV\r\n3NRQzVdSpYi6rWMcHUpfM3Uo++JKwx31ucJI3mOFAU/WV4lWjxy/PVzGzPh+\r\nSRXn3XnPS+CLSzD/4hefU1pnBpvqJ7PbRdA/omDZJ4ZcigEj1N+5GcAwDMoV\r\nhUYHfzj45jgW0OGvceQi8mR7RbXkhLUUt5v8jT4n0h6UJMkp/2WqAnxl4w0X\r\nolJsCLczPToR1tEBJRJ2pQXtSV8zYY8yPtcWGrnhi+Sm4d3HMgpVgJk2+//7\r\nTU73xOiIQUd/lCYbEk6Yqht8P7dGqnAKp8xydmw+nu4q6gInrW/0+Cqv7Re9\r\nwikqgxpZLNn/uuorsQVKj/ojtZk5VkYJInbZfE2sNUkb5HycmdW8Ux+HAdFF\r\nsMhcZ+7ACH4lCUpoFAvxhkSywMzX0FjKyrgc2zTWe34yWq+0kCFtlZG8x2z5\r\n6xkkKGfODGSrTcW+py10+4GxpIgXuTxYQ/s=\r\n=76ZR\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"fdc3394f68aa4fe496167fc6c9a6ad1e0df0e19b","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1657505351465_1657505397536_0.9905818272118492","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1657505493262":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1657505493262","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1657505493262","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c457e252f4f833336787cc90840c38a38a012b6c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1657505493262.tgz","fileCount":8,"integrity":"sha512-n84aMgXlCFe2vKPPjtOpffwPt+ku0FHTPBAzum7Gm+haUXV45dQFCPgZwNEtKwR132ccR9cKhISOgqmCtg4aGA==","signatures":[{"sig":"MEUCIFU+tOsQEARLIiMYkUHkt7p2QhtF2QKqHD+iR08ENwVuAiEA4rhakHnxeIquXm2PtYZWzD+n4pQR4phhCEggNEsrT48=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiy4cJACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq1SxAAgEa4ys/wzLdr5eKLxkztVygRhspJV4MomrNpJ8+uXA3vhp3U\r\nknG/b/doAH3yVnbKArZzcw7BVSyDWB2a7IJYozzI8z6e3rB38jImIEZVFW6v\r\n7qXb6IDK3+kNwEHKlfgaG7LuUElZ6KdxQRSmWpsnNRskVmR3DmnSMysjBebq\r\n0yuRuOSShIpufPbAQ49OpMsyjmALofuPVG6W4mlhAptsC6r7o8vQB7hrMsY3\r\njIE/BtHqqfBNT3FcAZ/ITXoNkqXFK+l4XLuSXspEZ4c17tgrFHWs5GGDaz8j\r\n/YIf353JhWINyDWW440FpyHUvl7iGmWM726BMKCYdw6VhFXJffiXJpCb+oiF\r\nv/EELjgfWIEhSHgNgFtqOIZzGNomfABRdgu2stpjNsYg7zzrL5Ad08QN50ld\r\noW/1PPC7a6lvbQua9//onu6TA4Rh23jzK2VEKRnBCm/jq7p1VBQK1p5pN6Uu\r\nqdaJP1YlN6T+eoRCRGtpfaDQogsBNU4FYTyIeLzpRhzjJjqdBvAXxTSUl5dB\r\n/VL+V+LseXtUB+0hXaX3abRQ4matrZOm6dzg3NI/4u4bATR4dMsU1p/csOfv\r\ndDoZVkzj8TGOn7yOpnhMokNvEFNM5iD+HSVp2+e5aaTixoEmf0jNPOK/LIxF\r\n0hrc01eBkCachcNbvA4+KrPYssUcx2/1XLQ=\r\n=nYc2\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0806f94623e57bc50c6cb66eadf6f604cfb00ac1","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.7","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1657505493262_1657505545589_0.7552916363188247","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1658109887094":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1658109887094","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1658109887094","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"64277b864fd72c49ee9c5fb05cb10081a0b466b3","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1658109887094.tgz","fileCount":8,"integrity":"sha512-p+Vafj+dbTQ1Wy7HpH8kyj+hkcx4LbnDz6wAovBzj2b2cs0R7HAcdMV3rArxPSjunJWSo/5qseivaXg43gbW7A==","signatures":[{"sig":"MEYCIQDytdsq7b9iSKDSFQwxP82wSFuyCYVY8SB2Zs61Z75AfgIhAMHpSfP2OpaND6KM88qYOsdbF6P0OnnddIsSdE1koBlo","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi1MAKACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrP1hAAotCPVIcPXztcmHv+7fmITK1hOTGVUExyeC677w1OPOZJR8aR\r\nyJj2nM/2JM6ZGUEDq6twwhaedwTx4cXSpThBW/pfAdYDVJS69rUJxZxWefSd\r\nS5olExOVpqt0BtDkDv1pVrWqiWl2Jg/oz6e+hf2Wlu9ge6EI7IDG/afj7X7/\r\ncETAigAfJwyDmLmu4KLA0hvJ0wE7UP1z2XpDUb75LZ6nKSMLwTD9sFAf7zAe\r\nFFjn6AeAXYGiN+r57j1D9ya2Mkbk07Cq9eM4E+y0euEatN5tqsKvmCGstW02\r\nGUdOeQ7zVKj4RSEOESA28WcG2nnsBrWd6E3zzNxV2M/rkaaG9mi3q93htXHr\r\nvAIN4mpbxcxrNTOFYe9gXl49X2+ZkoPAHDeCAn8V65a+55k5WH0QXMc7aalS\r\nzR7z/g8B6nZy4hS1NLspyZ48mLSBk297FRzjgCT/jr/+fgDluDVdFOo9eZ0i\r\nd8VspszGjB5XFE3j5WJ7W2CyFLvge/tZM/l1PTCRTPnjTddsu3GTltwERugw\r\n6zTCp0e9kZ13D/7yh1s4BeeUhg2j6YlDBRDAN05JcdDk/DWGHpB2C6lGV88c\r\nqYa5CDFHk+iCDoDdUECL8jbLINzFvBGQOTJTxEnbRy1PMa+hPD+YBQBR9OUC\r\nIy3fsnKw9mGr6etWw7UTo5gQTlg+mHBM3Z8=\r\n=X1xd\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"d1faeae902831da20aaf7b60908abfecfd8cc076","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.8","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1658109887094_1658109962130_0.8517865057427643","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1658109901212":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1658109901212","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1658109901212","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"79ff8d69e5596f2bf3ecf8a3e311e8572aec4aec","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1658109901212.tgz","fileCount":8,"integrity":"sha512-0bH45zAMcZ4LFNPbsHuUFFp5Epeo/XzjLVOBFQKELdXs2t8TgbRI0tO5RLwb4UTovzmNJ5UYcTGXFpBwYeuj0g==","signatures":[{"sig":"MEQCID8pzbeGED8IcZ9gY2LaFevUqRPH8zMeuvv1x4zcTU9bAiAoQk7HI0Gx2hU7AEFakEZPHum8jJVNXG9ZswYcb1+9gQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi1MAMACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpQ/Q//byq8HGBs7YQRzns9bwsRkleLEMiKCOJ8mAn1gw4gyJsGOavt\r\naDV5fI2uNatv+52RYPSKpCSlHaR9kHEHfWJiYM3WlfBRgaKay/smpM6KsN9D\r\nOlkhGqsYRSfL4Ib24WmhqFJD0uMfGvWvY3Gjr57/pXanHMiU/+AEL0A6fSUo\r\nKFip1wE4Jl9vGcwMzt9f74EdTyTwfk1IC90/BRMfMdRQdX9eCDqRaeKj/sor\r\nBXwEvWb/YXZNZ4Bf1e4eq4bgpTbJmRaUBDsMxFXH4u6RMsdN1Jx4eE7TQ8J4\r\nZpVs7O/E0mrPjxpNKgOdiAw6Gpjxq2oG9gmSI/jvLKUT1FZWucoBFDNtluS4\r\nGzbD84aHcn5BhUT6ShRCrY9psxdhwRVChcHkq8BpGSvCJg7G1jeVbff6LqFA\r\nI28xjvHrlMIuzlL8ly3DzaQOyFyBvkJjNNW7Iwh15mWyxIUeM+a1X19AeTdy\r\nXiSLZ0Fglqz7CVCt2GJy4OsVf8W+SaUnHbK100B2FtiD7DcVbs40FtQxsfwU\r\nmbdShtApVWHuWcZlx9FxFreMZ1d5A1u/YRyiCSJ+WO10m82F4bQX7ccrzn1K\r\nPg9NAVQ9qtSr+31qnxUx01XJ4XvvrHbnmBjugyDLx5HeOrVRykeSEx/y2WfA\r\nO8mBdA2JCgug10QfmE6BlkhTu4ndNGRp21k=\r\n=eNh6\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"caa5e798731a65c0452042bcf63bad39d140a32f","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.20.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1658109901212_1658109964157_0.2717954472825381","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1658109934928":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1658109934928","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1658109934928","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"0151e32ef704066f4c27bea8d8dda4a949ec57b9","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1658109934928.tgz","fileCount":8,"integrity":"sha512-As338h+eUT9d3i4nMtq4Ded/z7Wmk5x6ybK5Yz95mok7I1OnwyHOPqfDfFvKatBD6NVpc9cTfMsMwcqKC79Pxw==","signatures":[{"sig":"MEUCIQDN5GHLmy7qJ8XeVhaj237NvNipP6DEfJ2kHyTTRD7O5AIgEsLSvbZs/QopZcBC90xk6cV5MkqYrtdRgDPaHGxhukk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi1MAeACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoW/w//RCeOLA2aeeQ7Eu++zk03WIqazEnulot9E3T8aUISLknL416T\r\n4SA/wOlshkGnvvJDpvsEid+jYr6Fa0epgOn65IZKtLul+52+no2xcBD97p6H\r\nR1A2t32/2HmjrSSZ+lM9X6dm9AFHQtvBkk8+IBTGS1QZo6o/gnrrMFbpb4qN\r\niHe9eH01TatyDaK1KcDTuYmy1e3jY7Yx+vpJCPTf6C234jbYQiiKqu/VkVpJ\r\nv4CHwpBaqUeyCPuN84MB4o5fHHnReputo1X7WI2HPzyAqYm8gpHp6zi+4/tl\r\n0U72q3BatTkJN42kRiVDX9pTqGfhl5FSTqUYkdffCpQ8r6CPHEJL7eqN6ueD\r\ns+jzi9p181omRwpzErCKGrBfDlWIomrwouwoTclP+zmOGbZxd+GCsL/fhr6D\r\nD2OiQJrKldNHED01uf+Wk5nmdtSTkgTNhCbOoCTpMh+deKJMo3ev/iDSmv4c\r\nNwWHDfp2xjZ9CpkZaUz82fVI6iw/rGsfFD3L3xxjhrXDt/54UZ6km7ajNmvW\r\nB0i7byMlnn3Sa37774Xmuijd6JZ4oGe62KUpsOpkGzxXH1OuJos38XSRHscc\r\n7ADxjnF/2gziH7A6XEZputZeyLQlc7LU9vSICrOQ0Lp0JXTkrHZNV2BH/84G\r\nygbXMG5Ndy6tTW8eHz5yvmgiykUQbWqSsDE=\r\n=snxd\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"f7f1afb3494aa91963b6d8bdd5062cf05b651f73","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1658109934928_1658109982009_0.2631408834844555","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1658281516370":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1658281516370","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1658281516370","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"56bb1fca7be8f514664dfc8b0ed418653d361b25","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1658281516370.tgz","fileCount":8,"integrity":"sha512-cPZk2vruOwasNjBL3za9pDhwvx4bcoDKtxguBUPppQbAXwBVBjzDiye8RCKetzS68sEROqslTfWI10ZXjX+vVA==","signatures":[{"sig":"MEQCID9wt4dZP8miDZ/e3LBSpPbBQDa/3/6WsK6q9yJV750XAiABtWP/HMvJ+mXswg3siP4PIxWqh3D4GpEMzzFFqPiVmw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59950,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi115pACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqy/Q//ZqINf4s/szYOGB0bGjJS7j7TJj1NH5xEzCojMvQwhc7U9Fsa\r\ns5xSfv4g5hoTleClLP3dFxwEZLdxSsjXwOrzxY9cBd436lAq14uK9JxADR1C\r\nOqm6r+GP/PIsvELzkSjEdqkj6UG1Uu5xReqs5+Lrb2wOoqVNFWtmC2tXoL5R\r\nb3Ka4mBBTfBPaRJz8iAkszG92DDtEPOF/Lw0LgisBKJaYT90/S0UekBOawEK\r\nqYVr5aHPjjt8IhvT2H9WTtAiokEVV39zFrGMY4wL/+xBvwx8MGR0QpLZWGfj\r\n40Aq2fQpfln6nPXYQkkTRIdYnF56c49X8Eq7F+qKh48TCjTja4vx9XnZjkiT\r\ny0t5cxMegR4zbplPmk7du/FjdOevI73VCVf4cdRClJxXc8FdBAAOYA+rN2tX\r\nOz7ME1JAj/R/dcyZqafVMKoCYmzJu8jOIjNUynLKDtypxaDUyeWxOPhwgi/4\r\niKRnBO+R2NXqHeoT5X+TDKbR55UamToysfnma25bSnTFvv6PFl+f6oOADoyt\r\nMmVdJVyuEABJuZ3vg9OzFXwsmEt4S7ADj6wYfTK/WLdkXGF10ym39Spl9IXH\r\nF1dck7vzt3+mSy9gABFdTOF/d1tJYGiLAqt2fqR4n42PHBxpsEHgKMIcFl7Y\r\nhQ8xbIBYfJ0aYb5sqpyIkN2PyEpYAUH+26M=\r\n=TVCq\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"77bc00fcfffb4b67faed173dac771d0d4f0ad106","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1658281516370_1658281577154_0.12588688992540842","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1658714680437":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1658714680437","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1658714680437","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"fee78a8f68de1a322163c4376ec0d82891a7d965","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1658714680437.tgz","fileCount":8,"integrity":"sha512-0fQgq4W2+Xk8QVXH8VEBOO7d7WCpmO5t8jbtXIeMSm8RapbUYsrIpSBDLOeWAiO5X+EgxNeLB8vH9/4a6RrKRA==","signatures":[{"sig":"MEUCIQDHNjWGG0wSE/2jztOqA9PKiH+r1zd99B+S8RgWbIuYMQIgEiQ3DTpBQ6dYojJVmj/u7XhXc6fRfllMfK5R4yn7RDo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi3fp3ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrRJA//Xlbeqzi1f1gZkttwtwPuJfPBMbOPfXfrCsncC+bk57V3m9QQ\r\nGKf6AQKJhzdaJANssSOMIsgsl6qcefqEhH4Bx2NlbffFFzG/VuWcHrvEfPDQ\r\nlYGwjcE+5w8vlsoJIuGjfjIxLgj8XzJIrMKdKyA4R+PLbQL/iKqIFL+RtWEz\r\n5mNVuEWIj+FGxW2RlBlq6+ABSRgHLRZn9fsamuTXmMggj6VW621Rk8YN90M5\r\nqk+ACtLTA4L9121elJ+U7zUyjPv6eazmir1FFP8k8xFLzqWhJDMRIRH1Oxkb\r\n6LiynPxMfiZsTnoc3bHI14eYFEsMzqTClFb3VS1fQ1+W6CnUn+DMu9sIU/gf\r\npfifJnqx0O4IrJcDBva3brzUV/X1YYPiFJmKWWkt7mBkwmvjzJILTn1yAjCI\r\nbNvSeSOQtdEjPboqextGSm6tDlpw7aMTQDz+9XQ5+19tl88ToyRXSBGijXRh\r\nEFvsUQveFHTkGiAXFfrncRLwdOxtHIoIZqJzXpBCsuNpdVwFl+J+ushevwdJ\r\nMFfy/4pyEl7QQTWMpTtLFWwkYzPjkM7E0TS5GuqCXcO8LtgMgcgyuA0IHUtm\r\ni1qdRHG3wbqLQI1MvkGrGIE6D8vjWAkrYrBpMLDOtiffisbd2oSBHsHu19J6\r\nucDYrnrO9jWKThstOX1gCZsyFotYG1e8wA4=\r\n=SPvQ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2ac8d03a0761aaf2fa73bda2dcfe7aa0a819ac12","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.9","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1658714680437_1658714743650_0.7509856863054134","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1658887361101":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1658887361101","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1658887361101","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1c4022d802306e5ddf09371b7e37b2b1dfa7b2de","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1658887361101.tgz","fileCount":8,"integrity":"sha512-hP7pQDB0ZMexvZKKeDSkctQ6z6x+9diW2pBDNuHSNT2yxf4NRWF4xaBSfPEUAsAc3vYxYejl5O6UqPtXUqrCHw==","signatures":[{"sig":"MEUCID8yOIA339R/Vi/azbojqoYU15Zerm8xh+GJq75yw+wpAiEAqH2V0ZY6Qa6TO07yf0NwE/eUxCK1vWeYMiIrFBXsbvE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi4Jz5ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpj0g/+IjuYJSlmCiof5FWdRtvx8GomZUgHpFG190H5vwxqjqMihWyx\r\nwSI3ag8cJZUCmoYzRGCLfyzNxMnXqd77MDDeMaI0aXf+Y3vk5fj+O4xyd6cZ\r\n+qhMFm8DdIgFwEFqmbuLkRFDMx2gkEBEHhzDer6Ojf1dMMJIrP4IPEg1VZG/\r\nW4PIp88QIxKW7NcyOooYOt/bhcXvZB1bPLW0HgY0PWbhudDMjYqxHEQQq49a\r\nMtgXhMH8snfqvLa2Kwp924uclZ/c2NO9MxHSABDIIapJqTC1a8NYn5HkexL4\r\n4ZpOenaL91m4rT2xAZGPmb5wwbpYr1mvCyrT+TIkRO54us1VK8z1DI7gHVEg\r\nHnLzVE+6ySqKv08+Dcy1QrStRFXKax3VpyqkBncyw8cq9+jg05Me4zJhXWhs\r\nFiJGI5HpOI/IALIwcHdJc436bu696mj8AEzlZSi8/RWdJcbsw04mZwUbqS7N\r\nEz1xvshsLVqEdxtMu6lv2D8a/KXOP7X/8ObCNLgFTTBlzVUbEyPIsy15Bwda\r\nLH2+DArz7fZvSZxygT9t6GaGss3SMEkeDwu82JF1s01K6mg2NKuOAJ7QwoES\r\nCEk/mBxHOWhcs5SEFNtpF/IZlfpJcu+qdaN5D4ByHdHl2qBWweo793p5EqHq\r\nEOAL+UfWcMSNxdAIVC3zMWMqmiQpw7unFSo=\r\n=KVFK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"5d65d4a65f9d2ff2e6f1849401680e1573b4047b","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1658887361101_1658887417739_0.0920035993596171","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1658973717872":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1658973717872","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1658973717872","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"06d7e6ae242b9de61c5051b39c8575be4ca8bed2","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1658973717872.tgz","fileCount":8,"integrity":"sha512-RomLHy1alYO6DZeajoScGIALqNxdzBSrYIhKHgKwSskHElA05p27RAWxmRQWwKpWszQ0J1G5miL6NQqPvd5SoA==","signatures":[{"sig":"MEMCIGuOVuqAyOiOr1xT/YNK2L/p/Kxe5uxyTADcSr/U7Da+Ah8v7DWMHgx45u7vsmyHESET9cNbj+3bQja6MpdWDiVb","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi4e5IACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrjhw//XQBhsUXiu/2Fhv+p+PaOgfrCE7DdLpYUvT2Gl0fa1uGv5Rtw\r\nGTDMck9ifxW16z+ajsxz/+3z79QDSlg+qZG+EP7K0SEQ+h+hN+t07tsQrGdV\r\nEfxlQVRuOc855KOAq677jHBDpMY2Y/hvjs8Oz8AiGTWhU9JnJzRsy65zCpny\r\nMdXOgt3Ev6ftoazplhiJuHYO7apudtRJlTI87bs1xwZcAlWicUQQXynzL4Bf\r\nsL3W1HBFm8naDfyz/PmmicrWgbOmhVlXSqU1jZ7/a1LgG9Oeh9mq5b74DW8J\r\nKpFy3ZFvDdFy9vlFa9mADTEWQ6Lh2RBmoeiqDmeclMym/K/xgS0lny9s9F6z\r\nVgziNvWt+iLo0lpU3rIAkH6pr0vvEq6Gm5q4tnmds/0JSvCGLueEW28SNmSF\r\nO/S6l8/f3b6HtlUHaVS/WY2/9hYCCDsC12yP4DdPsVYerR1Qecz95L8S3LWT\r\nXMnZ7/wfwkfhM1OTHNBPbgMtAgr7mzYN0DQkSMBTV+5Nn/oFZFfm9oqxKYU/\r\nEjs9ctEGcj3KxT+yUzaspeD12/q3H80iuU1obyTjjvthLlq1N95j9jHnfege\r\nn+LgS9Wa6nK+1iOn7gDWITgbjrrkioAnkhsC5B2ej3xqKMj9HEnxJNeVwObH\r\nTNKWJuciH+l5HAPBhjImE8ldI7vHTuQXC6c=\r\n=T91F\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"85ed590642e502ed9f2e906be57c9f308dbb4f97","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1658973717872_1658973768062_0.4637278716599944","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1659319954596":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1659319954596","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1659319954596","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"0d69a3ed0e299c47a86cf76d70a7d4ba54163900","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1659319954596.tgz","fileCount":8,"integrity":"sha512-rGAHIB7QcnQHkJn3V1tkRFhBNq1tz6NG7iXuPt2ZrpJHFQCCdkKktmz4HQxzqhRYpzvSkC7MZi31h6Tbks6ZVQ==","signatures":[{"sig":"MEUCIQDBas74YILSOlBIiRVwJxQmzzgGuvb4mWoJf69aDgWzYQIgYjE47ezPiUIOIpk0w3ZRCgdcRNuQFaGk6lWqtpIjfE0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi5zbGACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoMvA/+M7mLSf8YlLiu9Lst1vihSbJ17PM4xlAPLlV7Qhyd+nxwN7RU\r\nfoH3842qFi6+WH2+dcN0WdqojKQblJWU5Cpm5K+QccaNVuc0p4TJnBDh4FTB\r\nhnQyat4K+/oHN6fzsYOYYeWoivyxNuxcsSknNfiiSknYs9kd3z648dwJmvuG\r\nRHTXjEpzF3zwBV3nYvzhCfoYmF3TIWfIkH3DB08FaYFcU1fvbnzZcAvbaJXs\r\nhMALgbyZZ0oC2eF/C3zweZTVm5hPk7qGN3lhFxEgHECz8K/VmGGftqLv33fu\r\nUUC7u2IzCn7ZuUR94Nis1p/gT6TQ9DbWipKTHOMkPjJsYTrNfYW/3eKGfmfS\r\ndmOGo6JQ8OJaMQHdFVFCSOjTjubbc1D2wxFB8jakzvpiD1TZpmsRI3yFhLGq\r\n0YZNYClmTFhcddbNjzbHCSQnPsr+fYx0z6ycg3lugdpg/cJzSqa8gHPwGMuH\r\nk2aPglgu6KV58gxBBdXa1jOx6MLR6H6sV6Tr8OeZEX/+Qqq8E94DIVOPM8bT\r\nDf2SOcBlI2RKCVRFGXKj+VKosS5fOiO9TlGvRHsEMWFdeOq++cYC01kQ8lr3\r\nYStBu9mGrwwLZdBeFtpRsNS59jxjCIBout2KRpJNTUXN+e6VqYMoUuRaXlod\r\n6n9XHmN39XE0SSWED7gz7RXQRQGWU+ousfg=\r\n=JKmG\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"087634ad2c7c012a281445eb0701a668c10d9b2c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.10","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1659319954596_1659320005990_0.061734579289406843","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1659405782966":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1659405782966","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1659405782966","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f2e9b325c25b43d3a6384e7dd0be9064e7347845","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1659405782966.tgz","fileCount":8,"integrity":"sha512-xnWF5ibra/e4lgmHQCSsArfpUrxTlPU5vVSzIyxAZC2appF3kVUM+9qeNGVmPqusVYYzHfEB3okZshe+2VNozA==","signatures":[{"sig":"MEYCIQCb5ct6TGv9KBCoMNYnAi8MeH1f0q6DyGUfEnoiAjnVPAIhANaJBt/Ihnqi+fh8tTKdaF2PfcstmGWcSW1IIUnPma7W","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi6IYPACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrbWg/9F5zgw5E3hMjqfSaBab7J4rPy9B9R9k9MYwVouOfnJg4Ir4Mh\r\nnd2FdavabOiGvTNY+0G6LZHnMEKcqvh8AUlVPYpp4xmHmVtrYWbSY8e22GeP\r\nsvAYxLxPT7F2NiSOMPHeK7gQAiL2fbOpaxxDxB2Mxnywf2MHDp1iYkjdER/W\r\nHR8SxzAzL/vhmXN+f/VdPdy7JZCf2ak71wP/WXg+EbKQznmxGFg/kN8a4qrQ\r\noWZKMuXh2xutqIILkqZKJ4/lCjy+KSXKO8XaoP03Qp2iW0JPNfLonTHBgRuM\r\nCqwsoqk4/ahpZbZNy228hdpmEhI/XAXBIIpwEODMdS7MN20toaYuSSw81zyD\r\nXG2lmwF/T3s7RJw1KSA5d0G/P6D7Sij/+B1emi7JSqN78NF9kQIa/6cWvDiI\r\ndI/XuNOeWBshhJWQMovDfoSVxbTDLKRX0NdDU8TSDlkstok6AToQmskDAHhx\r\n0DFehzeqNZc/ZsXf8FSslUy+M5NY55ZkKjRhkHQWWZyVmeZQ1ntYSBjx8cW6\r\nde7zvD/ZM7jJZO208icWSj63tNpNk2J7eGJNRWYoW3ZTQFwbstA2ppxuWR35\r\nnV33gETX5bUZRDVv/ySAbukmP49ht+D77CwkKC6oQe9nUyBL8EQeMEBd4jle\r\n6lnypBouENPbglobxnyp+5/3QbwxgB0CuL4=\r\n=T8Xx\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"30f22e3bc5dd62ce07896cdc8e895d0636e0304c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.21.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1659405782966_1659405839031_0.38743537455685373","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1659924257781":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1659924257781","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1659924257781","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c83e45fee277b48c404642897e218005c00fa107","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1659924257781.tgz","fileCount":8,"integrity":"sha512-ZTJZKDmmdfCNsRHHhQHJnZ4gvlaGyH6FqHQ2wqCDmL/ailjJudCQdhkrTBAUqjihF5vYowHcK/NaEMw+N/Hl9A==","signatures":[{"sig":"MEUCIQCM/pjGWfP6QB6CpEWl6Vfxrg8PgXpvim9FC2+Yf6pW2gIgD+lxhhvxhxCPUY3voy8K+nBQ6/DnAUac34uCqctDQYw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi8G9RACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr5YBAAhNJ7h8l3Twk/c5vwlrf9FqRMkCh4Jcls12EBb4VRIvUAkBkF\r\nakzt++/oPNsj1dcdfmgSc7t39sdZM2nXWHItYnCOJ1C5NMBYF3nLsENSZr3q\r\n0guIlM/lR42p842PB1IE74QgiTDTHqRftqAgsNSsvozpn+d4nqC6ZgydHeuc\r\nlpHsndnoCW7MRUhpByCnBSuW0AH3CLdni2NW+/+SVW9YlmFI5EwEREgXhOPc\r\nZdW8hlQ/nXWX/Kkc61lxFVYE+FvfzVog4EEbre4LUL/ZU+BH40wY1VKO1+pX\r\nhcGPlRLhvbDx5Nc+BDJd5bbwrSxssJ5+lpLZCj0Lt8iRZSn9idc3rD4aD+U6\r\nbeKg0JHe0tGMiaxH/cau/S3GJHtowjVJTZZMM8dHAjIFKaQK6xiXQffgQe2R\r\nvm/iJx1KPq//uv+HYuamHzP4Y+QB5szfgN0Bvapj58599nRPvwkk8lnVkYTn\r\nf13dMgpxcpXM4hEk2yEU2w4666e5DsYmeeqSRjVm+XxTPOQCrmfCI8ZftCua\r\njIaS1GVq7XlTL7eCq2OrSEWzwR/6t++9wO/faEtxtD+eOFLQXmjrZRPbWQIb\r\n04V+sIpAJnjzW0Vi6lCdLNNDJ5+8DJ/Y2C7Br7Z29isfelW7PDLQGPrdq+zH\r\nw4f/Vzt5erymB/oRsplVx+BUwqS910gAwKY=\r\n=qvaH\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"838bfb25dce26124e2aafef6a4429445f5dd3ae7","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^22.0.2","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1659924257781_1659924305223_0.9385648380911571","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1660269737621":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1660269737621","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1660269737621","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"98f2007c77560c2a1179b45c37870b1b1a561cf1","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1660269737621.tgz","fileCount":8,"integrity":"sha512-F73d2oOvJ4n4x5FBY4zHKoYGEdjIM8f/SrOltMYC3r0G/fHWXKgUzmW2pEi3gUCptQm30Ntt3mosuwKCbMM2EQ==","signatures":[{"sig":"MEQCIHF2IgGn5hTadn3L0k3vSsuF7Wz8iwMROn9S6CTaG1QWAiACz8jYbLA3fctOXwsNngr2riSTPHWjs6OtPB/cLwXl/A==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi9bTWACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpiWw/+Ik3f8s2yDm3OfxipwQv4oSbzgfPYQCd45JL1qMRKBrCc7e6N\r\nOAnpzoEG65hYThdH/pnp64Z/a1vKkUFo85eX8rO2e1pRT1nFi4Z8hiYQyw03\r\nv4eneR0xKdXdQiFiZcFPS3A9RC7/xRUw+U/eol8LKu8ys1rbVFvGysqJL3p9\r\no/eow3iCYUv3rQlHwhk3fxvK4yYBvp9HtEtehlpqr4+11KIcsOZIPCm2dQ9C\r\nJ8Ij1C+P4jBId+Crj61l24Pvu9oeZ0m7I8dKomjR/WzAoWHEZhLlMt2KSrUp\r\nMXRBDA3dflqpQPmqffQEcFlkSMn5shxYfMhcH43/fGfDnM7QkRfmifm0BJoI\r\n4oBNZBl47jW+Nll7pSJwDFEaZy51SXY/YaqF14hq1VCupdP4htp+d7b+zTpC\r\n6StZL13KVJgS6DADZmw+ZqqNaSAOXcPB/Z1GM+/SDbxAHTJsqQmYu3GL5LnQ\r\nDF9dYFwc+AvDAV/ToJvMZ+xbXJRs17jkkNdysBfr4xXsx//wp6fyVFplS0kG\r\nOS/d/hjqLPWJsmjY7eHCgLU4CEzj3eqQ5JIUAwmex8AbxY7bcBkZ83p7D/aA\r\nT4bxGp4RAxZPw3exRZ+dfvbsWdfyqkEbsn9uzzl/xAlOay0rf8cMWgQ7rngU\r\nZqVVCZTu8EWLsfNEwHGEndWvvnzTKUw7DI4=\r\n=B6PU\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"13bf1465550fb32524dbe1119035e4e562f6b716","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1660269737621_1660269782127_0.40516174155449103","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1660529100798":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1660529100798","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1660529100798","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"092ba675c5f71dbb012d5148a68abd1ba1299bb9","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1660529100798.tgz","fileCount":8,"integrity":"sha512-FIvwMdknbJydx31CR6wPtg8MD2thKfd8TTsgh3dac7AwZ42fkWOUwelQQj3m8mg6S8QfgxTOVZUtmQgHXXhZYw==","signatures":[{"sig":"MEYCIQD6dXqs+/WglXPEbTilTIDO7piQYoNPzRutr6DCM3cYGgIhAJ97ahbV0EXKYEiGWBAspzggjed9fYee7lGlG880jN+z","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi+aoJACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpviw//bN74UE/+kiLwesdFs/GagmzjhlEfmnLU75gqfbLbM3D06jkA\r\nDs8p88e9tMzFdJvc8hsX3hEkOJ7s3FA3y7kZRRFhHqv/4cyHtNIAx7L3oJ9u\r\nLA6af10R8pFk7g3DfBDUTXjKMf76yskrVgx+cjNBukerJ/ZGmSOKwvjV5jJF\r\n8TZndXGhjvSShtGVy0m78eB6g/hvqHmjoqSnZ96shbAusies2znO/lfChQgX\r\nrjj6hbn4OQodtp90iP7WPN8A5KSVnI7wWtixssa0zZ3DRlfVCgIBHwmo9cwJ\r\naVNNXqe45CcAS24GfBMBIJ2uZbdqp30mfXUdBqv2CZIQzOhwo5RKdZSC8lvz\r\n/HQcpIyw8R9iEYP8i0QN6ubWlLFpp7w5pR+/MSxU8m1cD9g+QJM7BLg3mLQE\r\nl1t4lp+qlTLL1zZaZ/Xlgqz3WM73HtB6wP3Tp0yPMlugx/AyNbpwtnv9Q7ss\r\nsOXRejVsdynSfTm7WoON86HlAcF+JIRKY0TxF7AG1CvkBVcqA48GRlp0h/nO\r\nPbYLyc5ZBO+iRS7mEgEN7MmA/T9yV/Q8zvNQkXWnf3uQIQn77aI449POl4R5\r\nGMwjgvDbJmGBkh/OhOteYPRs887CLOl7HcwrjscwgKaurIt80kM5llcUsq6l\r\nIaHZYnPdINK35DYlra/CtzYIC4/lu4irJGk=\r\n=CqQn\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"7c465811209df01b84c63519e0ffa77171055d19","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.22.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1660529100798_1660529161230_0.23141026712481283","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1660529139621":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1660529139621","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1660529139621","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"6fba70f4df494e7699f4d11e788166a10a7c9fd7","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1660529139621.tgz","fileCount":8,"integrity":"sha512-0mxsWDOR3YrO+jaf8JVwsklSwCddlAJcPm1tlIvoXtHj/XNKZu5fskMaoiVmc4PQ642X7kKUOYFba/rNfl+6Sw==","signatures":[{"sig":"MEUCIDzTCXck/EtfDUSk+04QpOoeQoyT++oDZAD9KqUERmx8AiEA2kxuX32FLqPaFigMt7GA+D6wfsqxTUrZUHpuY8ykDsM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJi+aosACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoFLA/8Cbid/2dg67/ziPCvQhXuuMVmLLVY8FJheG1U25/suC3Dv127\r\nGHRsRk3jUwujv8NrYRFf5YUJbsrvNUq7UWMPMV55LnQa8iTQLaGn8OUfgYAm\r\ntK4x7VDc6rspene4JDwZwAoj4XjMjM15Ugp+1e96gP4hyuZMLjDojHKtm45M\r\nV4tLTKTlb+QD6wnwxARz/otucgmRV7fPenlj9HgueZfr22f7og9NsoWhsql7\r\nFPVU6WS8L7soORZnK4XZtNSlOxBWHkmwUCq9ini8U+ovUknfdjPk7jpBROEs\r\nT/cI4DSI3gufnsUhwtP2JuJHc4wtRqdEp1TT8yzZn3Ei46DGw93l9SwJek9U\r\n14P0bsW4201qMYJD1iFlerAP0VPc7U2YrduzkhTCSUWQiqASA8nORdSu6jOy\r\nZHmGiieaq+rrq4HbMytWeP8pz5dDA1uYhYgkjH+Lu34iw1hJVFmFVB8wXJlH\r\nMMtRqrDijcwHE2SVbqYDmj6T4kpmjcceLUZOVh7McldSMDRum4D2i5WcPCz8\r\nZNt70/n4nqWyroqghdZBbB6fIoPZpv6o+rj85nOP4KGga55Ugwz5CpEEWO24\r\ncObvTlMA6vqGZ/HOyIaiUE3bJZdedGB6LD7PPkgXHjGdEO8Ge5IggWnJPO8d\r\n9uM5FyOZM48zpDjagEgYMzhJVwgAV2VA1xQ=\r\n=XfM4\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"191fcf2ce0bd510e98c1e562f4bf4eb62e0c4a7e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1660529139621_1660529196659_0.5111390652330241","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1661133896211":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1661133896211","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1661133896211","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"e493d9da17f84d4457ca0c42f115c0e6ae21f787","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1661133896211.tgz","fileCount":8,"integrity":"sha512-yEmKVo4706DOjZ0GwLZu0SQALXPtzygQF932pzwyEkU/dmBlSXzVYtDiuxSPxF9u7nmyNnQhXQvWAEhAb5hODw==","signatures":[{"sig":"MEUCIBqeYh2v86PvSH0ozjfRH9kdKEy5Ale6m9ZsyhJ4uG6DAiEAoiglPjO2meDwDnPN/lEyBreTjHfZ5kDFosFS8glSsKQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjAuR7ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoI9g/+NwrjKqtlnaSj0hS4/VIkc6U2AqJBElZXIpazfbDXMR9Mcy/L\r\nOB9qI3ifdryJ6yvy7+LLnIP4fNhd55kobafstt/xTa9y3v6+tjN6AY8lPAx9\r\nTxDurTT18XSl99FyhN2Aun0vFdLqpS9JNU905cAaRAXPwuVZZ7Zc+a7bQ3c4\r\nQFKfpKEYYq5NMaYIZdUwuhyCLtzFgEtt+s/X9AV+ZhUtIi02Sn0F4Yzd0nyV\r\nx7NkOgabIFNeEYIBA17WtnUClRzOIPcC4Wa0KJHoVsfp53jm3NXdLTlmBnLU\r\npAiQMA5bwJqYFFBQxAgoR1H1Fdzm+RbVqZDL+BO3UfESFu2VkhjdA98Eb14m\r\noN5b7vyujeCgTf5AdTCnUs8GAkUfXWe8pKvF5R7PiEeT9h39a3C/P7lO4vip\r\n9ojpS4g7uamZBZmdaPRpE6J+kDSH9STVC0gQpZe4BgyU/n5V1OHwkSb9W+bU\r\nng/kJSufr76LHdeuRQNYjtikQF3aK279pZHUiQATaiJTgv9lyyo2aKnAgH1Z\r\n1kvX0iCiwC+Iw/jNpvhX2IJx7eVqejiznXtL8ZNuqKj/g2FWbOVI7kNcSKYR\r\nP9VQood5GbgnB0IsPn5j4dwC+J9zADeCu+xYAINdt+B95p4lMJZkeiQubeeE\r\n6HAydXdzdHmTqxHch6ld/W/X512H4R90RYI=\r\n=Q1Fn\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"de915070fb5a4b483086876e1be12dd7cdc37e8b","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1661133896211_1661133947699_0.01943165161854754","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1661738862203":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1661738862203","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1661738862203","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"64fe5e0735a55e91175a6f6f4d20ab4fdbbbb01d","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1661738862203.tgz","fileCount":8,"integrity":"sha512-uG7HMlPMiVYhm2/8ZWpdF3OoKq8kyR/lixi6WZHJ0iZBKehT5lfV7DxWCA4MxpMt9D31myCi4ijcV1zhrNrHpQ==","signatures":[{"sig":"MEYCIQDIndrWDDyJYgGg5YpmpLKyBBeFSjY+rz1S/Z7MHbwipwIhALdUfen2pHQz6JSlVCfDM7+BTOwLzNdZi3DHZSf2GH5b","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjDB+mACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrUhw//f/nSC4rKOjXlnlBaNRdYM6edol6fkLNvijBBtj0T3LE+MkvP\r\nZ0gy2J9RP1nWbnMEf1Q9+NBrMzw4At3e/Fdz2fvmsGUuOZqOx7Kj1ljEwkYs\r\nEolMwEk1FyXGJ7bcskwp2x8C8odfHejDS9HFoXO8XQlwDEwrbFMSFsVF0ysZ\r\niM5pbxHy6H2vVm/bkSsniuE/euo3S/ngD7CIVQzvEAK7J7+tIGobB8ZxdqCO\r\nF6x2IHo16LdR4OzIllCr6zP95kSXfD49Vz5gGbu20HfsVkXGFvh+0TcysoCM\r\nvA0/CEo9Jb5NVB/UoaCxrM0gFmlMRNSXbgj66I44Vo5ya4RzphTmp4t9XaX6\r\ncRl8et42/cmta1hO4sNxrGVzfEJWdRLkrdreDzE2eoEWg/deGHTK7EJXlfec\r\nerVTS82i5Tvs51mTH5GwMmTsJEqNkxrY1y+x/7Efh1CY2aL6jgyt1SGvp2Gs\r\nLbvocRuzU2hu4/pxUBHYztHG5XoaGbMGzZ/a8ppWYzeo9NmV8bHg2r054hkb\r\nNGTGmh6nTCGzjbF/Pzn7EdKNfvzt1A3idaGIv3gz41FhqvK/puwnxudLyedF\r\n1keQU+hJ/IuLpNRJ7udXYst1HYzP3EbTu0ln9LXqOE51le7qwJJyZe7+9mLN\r\nJNf8MBa9uRXLCMOrS0hKMXJmjR+DdQywHm4=\r\n=CJw0\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"a57a8597c7611cbe79b902d3803eea52791c1582","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.23.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1661738862203_1661738918716_0.8657628852246035","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1661738960872":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1661738960872","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1661738960872","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"a99760fa76a2993ce3a9334d067f94a24c7c7652","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1661738960872.tgz","fileCount":8,"integrity":"sha512-dtgY08r7sVhgvDgtLc3DyW2g3r6PdHhTlH2v9rMvZkaUuZbUJxfc038hYzFQxNnguAt7J0QgF1M7+/e+irtk+A==","signatures":[{"sig":"MEUCIQDVP9/9x8zdKsUUFeVAgwt7bh0hpz/z3ILE2cVN6j50JQIgSvF+1wbN/TjjquMMqs+aCOehte2/Af2espgsYQ//P5U=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjDCALACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpKZxAAkL4agNygy5dRUJzMqR9VXYOEuE3kv6ZJN2DHRmeep4T9ZOaE\r\nIaGxMB0cksZ8U9rg9gfLRwFj4ZieGrc8hn0Zl4f34bX6xNju2QudKlboC6Zf\r\n9HxSB0GsF5EC+/5ZJsoEml+q7biZWwXacbMhxYZO20jj5i17wWcENKwodpEu\r\nfEbKHd1OKFLdh8GDZuwf8ltphhcxkTgLu5X7feRIgSmO72TA/u++RgIXAlmn\r\ngFP5ieO5ws7qcIg40sYoB6JIGH+fT0MKHTuU6PsIPd1C+VKPM5fGUBALrFw/\r\nFNEcVBVAb1EQna3iOneMC7SCY0kiBTz9HQF39Uk45Ii7M8LaMTFEkMnM2yZ1\r\nhFLfP+GMdmRdpyNdxmlegAd59x7k5eBHbBEKN4/TTbDhFvQTaZ/mIUpr+ZCF\r\nEdmrEjPhgTGWgzqBfJ/l7e8aaprTG0PPq1WZLy0FIMfq9VA4wzG65crMDFK+\r\neLPQ5wpMhOcGzZIjyH3VE3OY07lPAswAdDS0vEeauo6vBJDnYucC77c3xvS1\r\n7ZYwbZ4+OPVnTyg2wiVO3787NpGJaIhObG9xHex+ZokVAszvzBDz9CwuUZhs\r\njsYP7gKky0yNQzHIFC1y21O11liS9OY9/nToxlAQFrob7Isj0ORkSfOLfoDh\r\nc6yLlnZ/1Se5Nzrcgcti4loUfbNdmXEtpZ0=\r\n=sd3d\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8f561a9fc2eae6036220c821a904256fee7ca062","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.11","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1661738960872_1661739019238_0.6705026089113455","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1661997888490":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1661997888490","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1661997888490","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"708a68ba38e551513dcb89512281acd535283788","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1661997888490.tgz","fileCount":8,"integrity":"sha512-YOKdVfwfCkKljsIjtVvVHr9HfVNQJN58hMk044fflkBfsk4djXVMH1Z34czWIyJzNNMhLlZFFK4+i+yjh0xhAQ==","signatures":[{"sig":"MEUCIQCgc+3AsmPBt4kiN1hGluqNvFtk6v2Q546KMoXe77MsgwIgCzpFitH/QIStBTfApc1D5Xe421t207UmnEE6JO8LoBc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjEBNxACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrgIw/9FqkAIRdqlnK55c6y3HoXqGkw1tvgkIGxsO0MFF+uCgn9vZ4q\r\nHqbg3rUOgRKuyQqPWb5Pli9O6jvKo52dCCu/JxJLZL9vebONjYGbivFnoP+w\r\niUCJc3lfuq7XzomskX2qapTjrS833zEUESha+rJJdiaHFhR8sc6zgakJU89x\r\nYaOV9lzr5RzHOqXPkznM0M21Rysgxe9Jm0hb6tKnoQZv6Jotju+lZS+zkVyN\r\nWZW6kwYhMDKli9hu2/0Zeo5dP42GcyhaQmqqFiyXFw1UUkp2fT6ejo2h+6sG\r\nP8VVL+5YkUN7naXyCC1SRHQk/OMda8/Ai/dgBovjiSSLgdfdvOTulr9LhwyE\r\npZOOE32Sx2LhSpTtG4NNjv0uxat3ddCfxC9FO+gfej4RODFSe/oml4/XoMpS\r\n2ApMjg5V+HLnQAmh3IXh0eZz0tMesGWgKP0ntiElEv4KVFnwbGgPdxJMcl6e\r\nPaN/dWrN9l7JZJUO7xHTzm8WruqTfWP33gqcAyk8AjH4i/Z/AkDRR4RHpIlO\r\nq+7tAAmYkaT7MO8W05omFqWGFxUruZMnp6NPjz+z2+SKv3PfvRELxi+sLTfl\r\n1qIBkIEZvUz0STz/u081tEszgnAuBu89A3qrg5R6Hf0cDl5s+ybzi4HVu8G+\r\na/g9bdlNwtaQEJ15Lr0CAire+0xj0xkWkL4=\r\n=uK8L\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"fb4a6ad435eb542b8e434d4acbea5fdb6d768940","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.13","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1661997888490_1661997937421_0.22410254531832163","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1661997907021":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1661997907021","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1661997907021","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"15db5a18b9b835c23f6e623ecd1277f9a846fa54","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1661997907021.tgz","fileCount":8,"integrity":"sha512-Eppz/sHOiw+Lk3Nx786D2MadunuauP7h6+pxyyFkjcKgJMq2o6d34UCbEMtxUp7Y0wBENiU0eFz5LZ/K4yBYiw==","signatures":[{"sig":"MEUCIQClFCMRYGNugGdaWyo6Ucz0a5b7HEdWQlbTfVlZmIBgXQIgcpouJe6PTLW/oh4iEzEzG5htSDXvfcvmt6V5oJAtVPE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjEBOLACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqkbhAAk+WKCDzq42XZXJqTbZos1Xwkb7ADYqGIRkxNALK5Enm1Q+Zq\r\nm/CTZqYUxoBk9bf6yJ5VcuhMFZNS/NHB+OW4tye45Q5xYWQnW6exU0JXy0l6\r\nonScIB/P/Y3FioIAp50YLc37gubnMqSMrD8raLDqGJAs3A+JHcmDt21WvLI6\r\nSmg/xLgF4zBFNRY3OdwERHNcXX0wuHhpU7C6/gumcoBH6jLKqpRbDKjU/TQI\r\nSldecDHPr8tOBjoWVkcOWbNyQPnz9q36F/CKOr+JEWacuHcMF2Whutnvhe1+\r\nsCYqb0VNKCVX0lQ/TbzQ3dlxhSw0gHIewc0qNBjFudOhMLzY0xm1/xmKjKQ3\r\n0y+sOKO1EREtZywxHjCdBgALAbU+aJV649QyCsWT6tgQTXsIGQpaEZLvQIxv\r\nSwFDaFQ3xKAQIyKsqdgKQwvjVIHUSy8aL99TUBlpZSzJezGUog3c37dYjiYe\r\ngRk6peS74tnOWnCSuLijc2ng74e8C0pCHW6dq23nyDb3TMB3lK24vn4aM+8p\r\n7ycqlcbkSAox5y07hlCRixmVDE3mzktgqE+qZtaBDC05WcLG5WuBrmrqLd5s\r\nkF84Bz8gm9psx/iTe3saR2JkOFJBIqIiBTrCLftOppIHo6tNaY+0XEjvTe85\r\nylCcyWheXcBEt+gobkUB6hW1sf9XSu1RMko=\r\n=aYfv\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ff430bd00a1a9913bd815d197adb011508603539","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1661997907021_1661997963392_0.9914273709535741","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1662382366553":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1662382366553","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1662382366553","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"9d9ea33cc597cfbc09e9719091a12035c7a0ebff","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1662382366553.tgz","fileCount":8,"integrity":"sha512-A6P39MELUht2Y8xP4Y1GwX7ArGZt7I/qgimK8X3pNcTWdVn56qYj5GMW4jX5FWJFlRtEh2gy1DlKjta4iD3n9w==","signatures":[{"sig":"MEQCICxCkTxsVAmzLxsAZr3bGXmfBsN81TnZChUkmTfXjNJ5AiAxSLjTf7FIGQ846fe8U1quurs0obPuZ3FlEMS+HlBCag==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjFfFbACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmomSQ//QG6bV8C1fAWiFHK6G6G6E69HZsA9TpJ3AsW+UPbRfEMzWVhf\r\ncgvo/S3DQmrJY0J1wei5ajV4YlHdHGXMrwWHKf8S1fCbdWzdWeF/JVsrLOGU\r\nX8mZMhZAFVBSB/+BbeEFQsV6R2K5FaUdXAVnurc1AFFdc+ECJrmjR2x1a/Xe\r\nmleoFR9jKLp6eOVO+JSEsWbZ/QNTAb6N3E1ru9/4PUszlb6wfI8YS7hD4Iip\r\nlZOihfN817m5q4lrR852yNqEsIAnPBvMLThMYyrbZoJSSyLW+aQWQJ+GX32W\r\nxkVznm3PLdKsdqNZTLGBHeVYf2AXJaYQ/yK2hhmddXLhFxTQIdRtUrTrXHd4\r\n23NkNo0+7WPWIwzksPJgGQ2O5i4UBsQ/lttlUOzAnO6iLuowhaCds1H7czmN\r\nyJj1IkzhZ2QL5XF6yVU4lcWQ5RRzrFHV/wzBdKRJhVUSPuKq8987rirBWmrW\r\nWAPqtIQenWLde5FAz9+MOCwt4YThzE3SGSvYgNOIX6I1ZchzWhfNIB4WimSw\r\npKg/VuAf/CFUKK+iS+pL7RA2R5SAN6Kf7etyI4VKRzDDP0XD3npj1tPUkg+6\r\nEIzaHJbEtTy+MnUh5O173iwFwOO+YA8qz++wKGrpy3TollSNQc9EdxpXBbhO\r\nyxqWxc5nl9vv0xqE2Kv5Xf2lgMvYMwXKK4s=\r\n=VYeb\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ca3b18ef75c1e54eb2c3c7350f2be92b7efd1801","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.14","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1662382366553_1662382427432_0.0550858595424395","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1663034663852":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1663034663852","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1663034663852","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"17d15fe9a9553d3f2880057fa8c48bac24d6b463","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1663034663852.tgz","fileCount":8,"integrity":"sha512-sHSqY48CIpGJd4kPjTYJOWR+CLJYcvYdB5hTgGQ3km4VUma1k5xV1EMItExcmYpb+25FYbkmRlWXmgw+v57yGA==","signatures":[{"sig":"MEYCIQDvfFxdXNsL5DHGUzonlOInhcRlkjOCtiKo8mDiEaJKhgIhAKScq/4jFDYz+vO4H2yZDJcjM7i4e7XacbcY22qSmTg1","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjH+VbACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpjUA//d3gUjVM3FVdFPMv/KVIhchKfeZnrZOcmg8sqo+DHqcgAdat5\r\n7zCN1GrxfmkEy49wAcHw784bK+HpTXdQHPOM6HZCbLKAxisGfQB9OYG1iyHF\r\nORjE9f7JLM28vuDh82EeXmXlpBsPRyJr8GDsHbK3Kmk6Dp2/PN4kQvMmEnAo\r\nRGI5/uHgBgGJCetNT9lTcMFgu8jr/nISyydybxOkUrSOXWhtvTsvHU0KIB0N\r\nOtCHh08ZfR9u2kSjx94eHq3Zn/BW8iAucyJMfU/4PAbJAvMvP6kWTaz5urS+\r\n5urHcIyCboN4v4bi5PXx+1ThJ0fvkL5CIerOS02TWGnWKflpkXCVSxdppNS8\r\nqUkhholMzeOfhoXSNagjOU7Awpwy/jWnFBdFw3XrPIqNOiUoz94iiXblkoqQ\r\n0CVMm1/7TYrVg5QDV/bfvCR7PXLBUUcdSo10BXCeShGlfk1YgDHERc4wxtfQ\r\n+QPgXGW66vMhrK+mNs1UkrQp0vTwUiPZ/gcGJCKvIX1gju4L6YE9/aVzuD8x\r\nGg2N5VK9Wu6RNaMhKT+76Lufrxd4hWxnmMH1Q82PyMgXXupgMPl7mEryWu/r\r\nbczhhFW9laroAEbDNLTq/G+kHM9j2hUHjntqJL37h3MYSOLXkXx+vZRsxgt3\r\nGwynt+QDioFtJn8r9b0dmP6B5gXV53oMQR0=\r\n=3fkn\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"0a171b107bf31d069e6aa87c48ec1e951ef8c0f6","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.23.1","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1663034663852_1663034715143_0.6574726997015647","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1663553270612":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1663553270612","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1663553270612","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"9f37fb455131ed56118bfcd97cda5ad314de31f0","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1663553270612.tgz","fileCount":8,"integrity":"sha512-kkNxZeyw49/tF58M/diSmAsawuQe2VDL4l69SYTT7l1Uq3af9b/3uQrorI21s0VemdB8vatTf205SvKdLnlJtQ==","signatures":[{"sig":"MEYCIQDtSIC8Z8DNXx//icTAwwduO/x0mhhc0dvUqDuFjw6yygIhAOYGzZTBfeRL3aDge/gHPvH4mhKeqD8GFjGgqI7GE19P","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjJ88sACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmroQQ/8Dpmu4eqLo77hAV7UifSZvmNPVTTo4BLpmTpBKWlUi2mJ4UxR\r\ngZj3ozPUig/xROkZgKoO4KZZu20xwnH4f0U/16wjVMPTye0MVm/e/ciAfyTD\r\nyMDcSUNNN8X7v+//5yh53YCPSSfwEw6a/NxUW1iTYCl9Z+EYDT0qBRH/dmIS\r\nnJb4oSB6IQDZzETjOztRTLLGsRQHtUq2nFBeQ6WBd5xIo2xEp+02itF5iCgl\r\nXiIC1HAtm0pZxEtHohSRRDBMuXIlIHfWF0SLLYO+0H+kSTDAyWqHw6OwN9sJ\r\nZpmFxX7G3L9rcW4OfNRn4cQpxMy0DgdEJSssoAmBzNGmVLlxalIi52UUEM+s\r\np1YcuoumZFyT/j3hBLZLBW8HJzNPVnAkZT27oFAuA6Lqtd50+f712nv2WfLk\r\nCbGijnPC6Ai0YVpcKbamnYkzZDhNypk9LsskUyn/wY57SMzLfyLqLAGdYD3a\r\nBp8M88wW6iI15L5vWKUVanrlJ53BmJppIhxDtFr7stlFCbzPuXTlynMwDSWw\r\nf5mVCjzKowPBxhLKPgDZnJVYXi7HKsyPB3Bmr06RPhfTlR/TFR/pIVVSUoan\r\nrykjw3xBS/rsI7cr7CdNBZDskOjQmr1fYNAZjjp6NWtACqch/0qIqVap629K\r\nG1WDJDjI8sIU3FIxeZy5gwiIHvpi/5Nh+1s=\r\n=Aw/j\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"a5328f03eeb53fca9f271a809fd9b0f7edda8bee","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.15","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1663553270612_1663553323978_0.7025468647460509","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1663898620510":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1663898620510","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1663898620510","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"ab3d9934ade78d2d8fb5bb045956d32248561340","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1663898620510.tgz","fileCount":8,"integrity":"sha512-YpFpABwTbFAPghstIWzc/b1hoaX40Q0Xajjy1KcT4XfZ7wdXZU0brbk5V21i6ZzXDOvPQIF4moSovZjbZBWXdw==","signatures":[{"sig":"MEYCIQDsGJEbYSyyds7jMKQHFU1vnViCN4G4oUWD5X2nt44/dgIhAO5CQ/BqX2QZ0kOMNPkxCVbpYo6EHmg7Ee/s3AueTKZG","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjLRQ2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoNnw/9FINf2gkX3ZtA+BLSdaAEKbGiO1033HFwcBelWc8OcLIf4C7b\r\nTsiRj4tddUV4MQX4dGOmxrwwg0T/Xg2834ocSJjnhCxHPGJEUp0aSp7nOiEx\r\n+lFwyTCKKJMU7iFpwSPl3+2iNQ2JNCZ6Fs7A+ZsOd1k/3UG4o33AguLduEFQ\r\nAxGew5jkBUJ5B8+EauiZjZQCrtXCkVzXyk63aOKgVCie32YGvpnRQabljbOE\r\nz+d+IzDgPF1chp9B2UriEVLEJ54gQQ9Z3tEEkBMgPN3jfi14n1Qxa+YWWfhQ\r\n8H6uQ93RyELlxdcz/lwSEtjGKx7Gi5ZlOprR684W46hiRIhK2+pMrMA8XRXz\r\ncPeEKw6DXW3cChPFWmPDaolvRj0audSABu22XWQLMUejRfwkX/TY0Aqenn1Q\r\n9mxmS+d9bGgQ1a4vPe02X3+l8iLhPfGduY/NQD+ZkLblSgMx9F9fp0WANCLX\r\nincQcx4bO8wGN8qM0gSAG1K5BjE9KBgkAJblTR35HCW8SQ4OCvUAq1coJLxy\r\nNKJDma7sFvAXm46F5cVqEj96lCWel5J5FvmOIHdtukt2sipN+wWvJmi+4jPY\r\nqrYV03omg2QZmaELrKyt5FV6HHbdgZlL4RAd3S60SjXWmZGgKr/IKOAm7iZH\r\n8hqQAk7CKs/532YDnh1DCsa+t7TacKaysTQ=\r\n=SwS0\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8e45d462008bf08ba495e52fda36e23faf7b89a0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1663898620510_1663898678702_0.695235135076085","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1664157959216":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1664157959216","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1664157959216","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"18af7c6d7a1402897de49d324e5f8f9531a123b2","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1664157959216.tgz","fileCount":8,"integrity":"sha512-HlKnDjfsM8LVjNSaV+I+NmNKIUNVvP/r/FqsoCG3yPDlqgXYJtEJHluWXh9k3GhfwBUN5iP9KEbeXmlbzllHHw==","signatures":[{"sig":"MEUCIQDw9fzKS/hhdf6SonA/2Gdu3pP9EvLSY7JYHGrMGSSe/QIgdA0XF8GCtW7yzoPfhbpSg5CqzO4K45hjXDcJ3zwiYDI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjMQlCACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoRKw/8CwJOPkB4inRf7vWa/4r0Aas2GEbtyNOH2SWq3aSegFMbDxyc\r\nfcUntZtiTmfIjwbI2u5H2q3t1jD1jBnMvY3rot9fmPinG9t5BLFZn70izdd0\r\nzalH9XW+lQn1L8j29rdx8IP6rsGcoV0eYsDaft8pU6Ab6hB5fpGRn+5pP+sK\r\nhtlpaAm4ED7/8114+DT+G1AMr9wJyw4BTcRbqSmgIKQ0Mjcn92+8uCX6G6/d\r\n1C1uJRCujEuYutvY850JkJh5FqzpUta7xNpBeBtKbwt9IDO24VLiM7rXlW+D\r\n9VUEAq0PsY9tO0o4dMDUxoO4sh2qPKELCpQJkA8cPdxWj4bet6gyqKo3xhI1\r\ne7ECrJkdHGazvY62pXKKsrmw3nK3T+xWiEcj48M2rEqv6hCcaSDraZ9rOXNI\r\nRPPirh6D0p7U/LULMnepniRWHuxnlTqjGTJ9RfWcE4Lc1rRmkrDFQ4IF369j\r\ncgkEBkiQVdAZRq0ghsPs/mo8ROI7D91KdEZZaQaHU7PtkIHIstWr+0blC0o2\r\neHUkszTz4c44WKUOcOY+whTlXd5yU64/ApIxR+1SIsv3TASlxdGC0mhJt8hL\r\n33bVa4z3gsGVAqRUPKN45EIdgMEWwNrZY9spuqUSxx3TQl1MLzAnPTVPqQTd\r\ncdvkfrd74UmlWKE/Hv3P2VloMg15WqVzMuo=\r\n=gkmJ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"6c2b6a101daef8aacf89852a3c453bb7f586206c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.24.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1664157959216_1664158017772_0.26338397093220056","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1665367698034":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1665367698034","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1665367698034","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"fc9913650deed0922f807d4eb71b188a03fec5fe","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1665367698034.tgz","fileCount":8,"integrity":"sha512-7K+BurVJofuQA1zDUsPFbUBi+yWvjUIuP9UkYwxtWhn3B2FBuaW5eIH5OIIu7VlQZqw+PA21ZMU+VdIywHubUw==","signatures":[{"sig":"MEQCID80HOrWACRyDNBzoz0gHPSLtQKXEjXl852VBtnaNvb+AiBoTc2DKSXAfNQj4jExagPE1E9QhPpJgeMUNgGFmpRWiw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjQ37GACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoWzw/7BlfIlKT05BNbLuekrslIET2bwd/JFr/p+0FG/s93CPbJzP0J\r\nugs/gfkhAaR3vXqyYdyZWGK7UB/wLwZ0Ltbpelfn1ScGR7HXKQnrkdb9lNW7\r\nJn1NstFYqQOyO/bGPWdtfQk+GsuQUuv+DK2k65+J0U/eCD6nTM9hdtlU+7OO\r\nKZHZQsMySCSknBHUanB1lD0CxZkeEbvsl974s8qVng+Nfiyg02gkkKrHLA8a\r\nXlYz6oZFjenCE5gVmC4BS3aTnxfNkNEOQemyT58xKOPTmOIZpvl1zB06yQAn\r\nNatr4/rT2WnGhUSfOAqJIchgNtPGTxiNGCTPQ3FgjA7XxIJfO/EQIgsPskpf\r\nExyXGN7JuWsvzUTTBVvEXQGpziYXmL9+SZ9uF8L8H2mAqw0hKQfaP8w72Tgs\r\n+8HYTU3I/G+CRKIwT5aSSbApt+QK0wloRp0oOicdPZcXuIFrAzTZvictq9ZB\r\nCR3HKtdDahnesWOLQl2fTwEt/+ZYTdafSRMzOZe/DyjD235m4jaZ3GVlbC5v\r\nKn8rMmfO40kBJ5L4ytii3kirmRrFShnUkTmWQXALQqUtBQqR+DycoZqqrVTy\r\nhO1rgO/VXwPcoVAZIESrKFISa32vhvZPtzG90qhmktMcqotj2wWNNJwEr8+/\r\nBMDgQ9BZie9xWy7f/Jj6uA4AlVggmn5LCBg=\r\n=htxp\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"27c1477cf93b163e836d67d3c03f92557cd1d7e1","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.25.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1665367698034_1665367750272_0.16875535994815305","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1665367877607":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1665367877607","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1665367877607","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b9492a0d0e8eb8f4a13a189a2567b65304ca849d","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1665367877607.tgz","fileCount":8,"integrity":"sha512-rK1kf8jQrKwu53sLmNgFiurTqXJEX/OGq9pDZ/XQbsdzjFOclVJGA7/wtVAhn6Lvz+bEXfXCSxxhK9fMZpCcQQ==","signatures":[{"sig":"MEUCIGkWiMf6qQaRJCaJCzI4kgi2L9npW33OcNNuRad0fGtlAiEA1ezRXC8Q70gnXA/77k+InblHjst1i8wWyGzc1hJP02w=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjQ3+CACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoNkhAAjxPykCSw/do+VGS1EbKNfiy4dNtlACMruwrcAgZnxyuw2EFh\r\nwogqFRShpTmE8y4VckpEeNw/UhDOCWwzj9CHUQTa1lKEbuUifg0wfRugYle9\r\nF3/8VbTDUzbjFtv+TZjdlzSYYGBkwgYkf8pcXb6ppeoyFuwEPzhgGYRjlf51\r\nBOfgPbjI2E3e/6XoTXzUCDj0Q4y2ZZG/NsnB0dkpWDKKW8tdWfvya9yQ10ni\r\nwaNPnZosXNGVHWUmgYyTnjMEM1tczqoumyYNsSkGGj2NA49Ahb2ZtWekS0A1\r\nL4LMEND0aThx+PI4PPGk+EUOlQFid16Og32DP2q9c1MAD+sh5WJPN0ZZvBKT\r\nJCbqOrvtaiMvTw+KgGOl2ziCMFTsKyn7pC1A0R7Q0PWnR6h6f7IoCIQyEAZq\r\nsb/tX80KZt+ya42d5JOEje2Ft8TwjsjUMRa8/Wafl77pXxpI3/wPPMFQZltO\r\n3CRgbRoGEYnIeb++bjCec20cduYdf0bGEJuLUrLGpNVV3Nv5SA+2OhOzTrPo\r\nsYZlKKZo6nuqiE2Sr9AuLZOltsxcz5gegrgNIc5dR8GigcnGtLYm1xjIoLm0\r\n4ZDs0rHjYZg7O80/ob57R1+XoJAfAog+wU/9+2UZKJYuTSl+3pS+QMPggdVS\r\noVoe+MzIlJ96aha2MkYKNIQ78oLN04ZBNI0=\r\n=5Btx\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4da3998bb7c5f99c80580f8019457bdd90e32050","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^23.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1665367877607_1665367938647_0.8211368987607888","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1665453779558":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1665453779558","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1665453779558","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"0bb44a3cca0887235ea150dc331ded335ea0f12f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1665453779558.tgz","fileCount":8,"integrity":"sha512-sg4dmmHdB2q+x7VEipx7hObzwY0akPOq/lDNCEwXpIy/HOEoiUSiJhHg3J7m/i6rdqaym1KwB5s/qumO5CLx2A==","signatures":[{"sig":"MEYCIQDIldBknS3gHsWRB6Ilu97tQEfeL++2QDUQhm98UJDAwAIhAKlV+uNEm/EMHofBl7f1uElK2i1SEmNTx8ZaGlasjXGT","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjRM8AACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqKpA//ckPHzHcU38bpiYTeLubwnYjipYkWQxYMlQHTgXUImktM3ef1\r\ntjc4Aj8FEIvP/ZEwgAmRkTOI0QHYHaTzUH8FAw+3Jwwy7FRSVHC4m1GPSML/\r\nj3nRyxis39pmRf9B8spw9ErAvwtRf/vitgCRX0dzgDaNtAKy/PN0ZDlnnGsV\r\n18njtZ861jh4NObOdcJ9cHDCY/Upj5fZ8tXGBEYBx0tLZD0FaBQVtCty+cLv\r\nfo2JIs69stqIsBOPpW2xxppfjtMqs3G3P7xxuWo8yZv6dC84IX5WRoZ8yPP3\r\nCO2FG6KAQRiExwZxWbbArbAgaifjJBuxb2Huo52IjG49gnQaJRkEEfKsgRbL\r\nRezHV3blOx9K8GU4aIvBBwvPFP5FN6qv51HOumJY4JnDaqY9nmp7mXg85NPE\r\n10gZ5Ep5cPqgdMcPgIYPDl2hhHDq5je3PkQvfPUQ4dAeDmRLhLTzL6ikBty7\r\nByXPPnwqztU6Ui2EEHXqOLBonKl3rD7YF0ndR7iciYqrC60wAPBY0EXlGTP4\r\neCCNkX9i8pPo33/1V57eMAKl+642T1f7w4pn/uNskCVHJJgdBzE6DpDbLk97\r\njoXl7T8Jn4zuSyoISiEFoGi+zqzdFS+P8Ibn+a2EHUEwuMRP656zl5g3Wf5+\r\nhpq8p+Vlx+nR56Jlj8OKunvEXNwwl3d00A0=\r\n=I/7Y\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"c1f648ea3bb31a9b899f03c0be64d9f050509d72","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.16","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1665453779558_1665453823997_0.40987990609353164","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1666144978962":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1666144978962","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1666144978962","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8f39d3f13d59df24b7429ece5f4ebd1813af1e6a","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1666144978962.tgz","fileCount":8,"integrity":"sha512-OJ+AE+aNNEuICkH8CwgSMoQ41OJWF/x/0O9zrdRmi2KvukhJL0W7cyv2zcs4cJvLBvBaTmuPwyHqMMJJJu6ppA==","signatures":[{"sig":"MEUCIDOx8BQTSwXM8NwBMpU++4jC1TEH8pT3ZgRu9xY5YkWKAiEAqDnqjcep8fuI6I2I43MeOtOOXJyIaj6+H91suW/M1Fo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjT1sDACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrLnQ/9FeRygocdDoCWNgFc5+HKnHDKnneT6SsVgBMjZTkAuR6/vDnE\r\nYzth1JgKnOQoR2+fey1EGN4hzfGY9zBxzz+lP0RKKujFk/dcJtfGJZ5k7M8e\r\nbafa/lbA1TDq1LMhs/fvhPShRk1t58ZspRy9mvv0myLqFhgVwHpxACy7tDxe\r\nT1gyGhqYGb3qcE0bACOxnCyDvlsiu86SocE09oayyKWy0Nse0Sb1D0HVr5j9\r\nessVc4VDX4CerD9NP1xk2E0Kh+NurCAIypzz13rBGofX78cCxz7LB0Wo51eq\r\noBJ0wD+rQn4pCO0Gtkfm6gDbCeTtdrASKq/8T/Pb4/tenUt0SnOagWHZcWqv\r\nx6DkfaZAJtq5jQ15/24IVNc63RlavWIF6MrHgTDn4BRzyuBUP6G3GDCi4sFm\r\nyZUHwdwopfqAIO/0FY7kHWhgBCCLjZbAkkpnd1aSOJUeqpyYA5eNFHfOrO5W\r\no0HD3R0y6FFTKVRDnOA7SaEXq01RqMrP+8Nyhad2MYyTbT5GBZ030+JtgNhK\r\nxMZwzcS7olY6GQjyfw+GcT3r+PPxNX01QdAWVCdiyhyADH6HxHcpBopAZgSh\r\ncgV4x6c9h59wrQpaje5yLwhaNQUuHFSb1L1DmW6Xt6asuipAGAGHt0vuRkwH\r\nWgf4k7mMiil0BeFSGYuwbtkJZp5xK39QNUU=\r\n=4505\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"c5b477512b870b6720c19b5906eb573c8a794acb","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.17","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1666144978962_1666145027178_0.5398631244091565","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1666317907483":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1666317907483","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1666317907483","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"18c7e317b360f80c0c5309b4f00cffa35e3fbd4f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1666317907483.tgz","fileCount":8,"integrity":"sha512-Nw3t1kjGjwJ58ANCQdptAt08geYEyEFjPCf+ak0C1jCCWcupLhAyF4ETK91yw1Uk+xpVrKHpUzxIdK/A4MfUhQ==","signatures":[{"sig":"MEUCIC8Ym1Kg167qudqA9PVFYYWJQYhA2YZ5Xr1WagH9x767AiEAwDHNYiidMlHA9LohU12LuPN1vTMk6rlf3ir4Ne015aI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjUf6HACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqCkw//dsOmAXifcHsgHCz/rNE4s3tRCuZcv0iCFzCE/9wp1bF/ra6A\r\neWVV4967BPq2Urid4rBhXSkc+tVx+2jcpVxInxQMmvCcBqcyr/8rIvxKW8QR\r\niiYhYn5WQEqEXgcS2g2Hvt6NrXYU+yd0MvgEqJ95ixMTHTvBiPq6zj9TjdGU\r\nhgg+Xd81V3kF+pK07A+gKRqHVY0jqPgpGUrVJ2sO7nMW7+UKRpeVpfVfK/jj\r\nq0wovMG+UMI+XY20pkxTRBIfWzddRlj63I5EH3pobXy0eqdxWiob1ZWarsju\r\nvjbvFzYodlKGTFvGtUMzrq2AeXfptyneSca/UdrQ8fAzMAHXfRnoIfx/hYs1\r\np+/8rUECcfOo9++6IkzV2KvkAh2WH5N6YTnumxTinihDnBWMhsUR8VfGDlL/\r\nPMRBnxVT8ty/BbD4zkiwJgiKwSLkkCl6et7xugQhHw8afvqlg5X9gMg9wMtW\r\nKWHL3PMUKutjEebspJsgsqvirz0OBA1gP9ZaPwGfmAfnEFnACFC46o+DLQn1\r\nzPiAumC+BAqzDtP6UFPxqLOiIp95vKuhMhEexTcQ7k2mn+a1gFYamfmW+WIh\r\nqY20+xkkw9WAkh6GGrpdstGUELBYUx5D20kv0X3Mgr/GWsWJTHVvpdxuEjHJ\r\n3K6HtCAPmS1Hf42Z77gCYvBnGHy20Kfp214=\r\n=NJn8\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"3bac499c45fb71a7b2a9352e247e7c339492baa8","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^23.0.1","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1666317907483_1666317958907_0.2791878569114723","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1666576903167":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1666576903167","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1666576903167","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"0d6c2268c09b9e4f96cb2467a74ac97c10649b1f","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1666576903167.tgz","fileCount":8,"integrity":"sha512-RKiS4j6I2ACLWMeSBpN0dRQDAaOwCrM42wo1v1a2nHNljoBHx/mC9Qco4tOmqsFBezqNHqfXZdAYJC+9vP4UTw==","signatures":[{"sig":"MEUCIAaOmmRu5LXXv/azOw2UisVWw+CQhyVCuxBsaBt4HojrAiEA0TzCvyRAUNCdiFl73BDnsp9cVlO19i72oKtsTmf2pH4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjVfI3ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoipQ//Usfxp5jczR1At6p0I4k4wOMjnJ+nWRg/7vZAwhOvBFgZmfRq\r\nHJtGj/LG69+MUJgwDgPAXaV+2JKeVoRnAVg51SSGleqSnaRze0pdQALveX42\r\n+0n+sXfkUtuoCTuoqp5f50P0UUYXkOoCv5eKkSQp6mgfTZ4qB/pe0GUYxilR\r\n+I4Z+PhDA1KnnPBANrzPV9n3gsxyB9Vd7TGkt0YJVlwuBSLJH+TMPqbn5xO7\r\n4xd6p9uk/Rgzzyw05FmvrzrO8gLi0HtBCoqFiPeqaT3MZz1/O2yMhLJ+yRlh\r\n95zgVa9oKSONzHUqA0RrLtypaagKnuJyV9PJQS5+ulCIMmNgRUir2C1eGPtf\r\nwZypTZFNnJfiByBNzuJ0O+qkSnNhz/4PiCq5VNBFNVKp8vsm2P0d65oClDZ2\r\nHUfT06bi2bpZYWkeXxNe1UUSBNXckE68jzEOcRiAh5aU+Kdx8zsEgbxrTi0c\r\nkpY2l2zuEE1c+M33VAPBuCjGfXhta67VbPKYg7d9MrOqN5nWZ5RYpJQAj/l8\r\nuZR1nIqo5P5mCAT4ccOMwQFRVqUXsnFO6Tb4z6kHyJaeHnDsa0XqV8CzYxkR\r\ndE4PgkuTtlgnDvxP1Wumm2V+DTdW+MWQ9aLuM4bJYjLVTenyS3RStxeb7s48\r\nsRLaeZdzzlXi5/7eIKkqMe74ujGBez5hZhM=\r\n=YpFD\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"decd8c941a9f12d7856ca53007aafc3db98e30aa","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.18","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1666576903167_1666576951340_0.4353393113024062","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1666577031364":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1666577031364","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1666577031364","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"d3f0479c9cddd527708064cb531b8374aa1c3425","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1666577031364.tgz","fileCount":8,"integrity":"sha512-zZJL17/xrIZpdL6ZSHBKN3vgxN4lUCDx34jJ0AqQiIC7oV+Xydku21F9Tb1lLMjLTznaY5Kuwf9JRD6/ClO89g==","signatures":[{"sig":"MEUCIFaCx2RByW4rnNEGdmKqzFuK5x+LKZGWtuvI+RzdM1rCAiEA0BVkXMW59+JGwDIBUKunvU0xPsdDXlzTewR2OxIWy5o=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjVfK2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq3sg//bV7a8IJpyTyzCZ7B3rWT9na0DOoBkPGGetYhnGLrjX8U5DmH\r\nRjUNerft+CyZ1dF33VIZ//mCdgSTnVdiymoMF5xD2+MoqPuTSLi7p7wV7oCM\r\nyGC5rnpESzTuK80r/dgDFsJzuk4E61B3ZESQiV3H0uTDxyf95uItG8oNB7vR\r\nQM7TPCPvX9Pw6Ho9vqT0ZToxdP09ogEpMapy7nn4QWQtx9B3/TTS8mcEtTKF\r\nU1BIWv3DOfuXYp5b+3xgfQJ0cMH0D1yRNbrkAsjd7dgckQl6M1gLTIbBZgW1\r\nY4uuyZdDK6JScfJtQkWVyeEemNcX1m1XKs47SN1iWox0chPFuhS59LUiUwJc\r\nJ2VcbgTYYJ/yrXVvQW1jx1QMmzZgbTIbr0QnIwqPLlWDsIZInGS0LoRj8dsH\r\nFOdnjQ05qr4KTMeHRXr2ckpZzbMu9ovBehqy70Ws4X/c2Jg9DUB8PNWVt6M6\r\no5vL+Dzikj+iiC2YQpJl5zPxi5CZHWfVAqkU5m+JVVVXAenBqnGJAAOe9SmN\r\njbQtdv/5cdrOl7StAtSBFET9MmjH709FJZVsJRaWir/4r3Tyb035tYBPS5+B\r\npAutuxRyllPsiON4d9+XzQtsevBvG35D6IQSK8/CIpHTs56lKtsjpDrJItEY\r\nazFyKVkkWhYa+Va6ML5IZj7+VgYhLU6UuMw=\r\n=W4Cg\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"6091dc6767af38c1dd5e56668d8a52b9a92eb585","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.26.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1666577031364_1666577078156_0.6971739419746641","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1666577075239":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1666577075239","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1666577075239","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"0daa4c6b16d18abdc9f834c8d01f80e2c8f5e043","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1666577075239.tgz","fileCount":8,"integrity":"sha512-VGpICFBMC9XBLCYXGzgd427Fr1e4uOnpeavnrTy5o/1dhEE+1rFVs1E/UWYt2g1hMXrTBNVqTcxlDOVOfiXG6w==","signatures":[{"sig":"MEUCIQCsIYR+Eb4FHHTMkRU5LTFSuNJgbLz4klZKgSLnUO+DCAIgMN3mPyxP9EjGXmZPNwOTXh37IFiKd1/p7gOngc39IIA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjVfLpACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqUAg/+KZorIQnncfExKoQj52i3L60P1GgW+AbOjjAm6F/vVA39eark\r\nqtNgwGzDbta0vdWXsZ8JHjltwpXY7suTzKVPLAnHNbVs02AojdA1fwP8+rgt\r\n01P0pK1YQUp8PbhfzdpnZPP9x2SyfL/Sj19VGV1lkePkrpUdmn3kxAZqn/D4\r\n3RprateNjTXnIvJOPChbr90fxxzQhSaNuDJAbIdmAQwJzvCVM9twcsSiww7x\r\nPfYJz2wQtVaYKx1Xgz6KhTCZ24/hcT5ngXdcQhs4AB0XlcNGXKJqmPVqV6yA\r\n+hGXJHGrXumM5bkuuCkq+GQuGUcJo/30jbYYYHsdFAQkZUROUEdFbJvX/MRz\r\n+Uaq3/6dyH4KuAFi7By1IL8ggcZxOaO8C6m/bO1bGmVMRsbSsF+Fk9FOXrA/\r\nLMjS8l6Wm1giX9XZahuwzHM9E2b/gISfqp6Qw+UabarQJdOlRpwl/Fhd2Tc+\r\nkA+ZNXtpQdb9eEKc2LzA0HS52lP2AUL5e1Cs7i0QnGaMlkoHa6r1sgNryoIs\r\now/b0wOERO+sFjVaHGG2+K9EcwpSjAtSCH/x0bokC/RIZyDuNievdgLE0C0N\r\nVx5F2j86vI2f480a/MtVC+pqKKFuqN7Grzjl1Nt13LR28Wv4WqXvRh2l0jl2\r\nnIK4SSrmlby8O/iR03BL19VBmQMPqjBaCEk=\r\n=5U6h\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"458a75352b2dd5a84be54ef9e1392967cfb7dbce","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^23.0.2","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1666577075239_1666577129474_0.6025350653844712","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1667181742373":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1667181742373","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1667181742373","maintainers":[{"name":"akarst","email":"alexandre.karst@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"wandroll","email":"wandrille.verlut@gmail.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"164040f952460a1c54b03fd5033e8088afbae485","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1667181742373.tgz","fileCount":8,"integrity":"sha512-DeDXUc6WolpV8fpnkgA5ORK7qInliOwplKzXwBut8b3rswX/0vBPO00bZZ3MEU8Rr//k48KrkxkTckirgRemPg==","signatures":[{"sig":"MEQCIG61o3Qrbwo3eioeUSvh7jx1DLE80iuRF4OFueF5MD2UAiA1++PELiGEmCp62DHUddtkVdbr0gsFmfggFKnltdDb7g==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjXyzfACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrnyg//XgWWfoHrGHl6mzuqy8QQsGerNLA2P+lk6eaMTZ0nyB0yKDMK\r\n2yRKyg9X7NtXVeWj5Wgx6QSJl6gUgY6hO/fcX5aBFtKxx699RG6sZLSc8YQ4\r\nKjjkcGJA1+dP32RG9RqEydioBKeNIKX+Idfvfhx0mhw3DLSIU5AyTiK8zfm7\r\nrMl4vj1OohOY4gnif1UoDtsCyXd9qRHYqdvisK4HqQhg3sElpppfU8x4SW2S\r\narcVJKZqQuo/c5Nu5UdcrvlnUb15P0rslrtz8KeeYoDTzs8ymJMzSJ/jpgpY\r\n8CZau4XMYr6dVl3VZz2VXw36kIzRDtNLFhDNIWGAQBRHjutOxFSgQMSlh8Bl\r\nlmPuXPqZn8GJdTC9kejRp4bVucx8fj3avAvvCJ0cv+274I1kuzYImsuvBy/D\r\nA7cqCIizI1KlDwUDZ18a7hf0bdm34OD1cSIrmdAUKhS1zi4ZWGOxJmwoCHQR\r\nktzLuVfzSqQQwEd1r0qYdezfP8KCPJxPEsKThleGyz1x4HzgPPxyDUqW5ZiX\r\nzMBhUDlxOpUAILIjC+tXAuJfKG24cFooqS8Tq/sRIL/0RmOXsuW/ZZvDsa/W\r\ndwRd8/ebEEnw0/MH6t8bb19r3VofKZtG04aECwtOVTvLtaa9ZOMjY9CTd+Lp\r\nFi4msUbmzGZNE9l/SBTvgHSHVybdIecNf5w=\r\n=NFt+\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"3183f16b1911c20564707caeaaad0db89a4ac4e0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.19","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1667181742373_1667181791605_0.5741255760493817","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1667786536916":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1667786536916","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1667786536916","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"381403ed3c6d4d6da2c3a69723cab5ab5bc0c6ae","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1667786536916.tgz","fileCount":8,"integrity":"sha512-+YxyGUyzDQhGussRWcHgToDkaKN6kf9eLilGo9N8kyEO3JARskDZQwuRP/ppv8FA3YADM+iNqiwFY35sWy5BAg==","signatures":[{"sig":"MEUCIDzVMNphHj14fO7Of1BqWWiSZmH81oOFzlvSgvYB5XiQAiEAoF2dWZxGjWDpZp/7bxqzBquHR5DCiVMXKpt9ebcXeqs=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjaGdWACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr9AQ//ULa1Hr+7H7zk0yoSUEWW9VoJ3A3NPxC4AMHj5Z24gBWk+9z+\r\nVr5URF1LI5dNdS/gpCsCgXteqP5UHkwjL5n2l5M2QYVeaE+jYllMvofALhnh\r\nzvN8SlZCDzGQfTzNpAjOfHudWZYd/77JoKjRPs4ZvXSkZrUt5EFVdqtrbg6E\r\nRAhF6X4fu34BV4TrJq2CL1Uq2IGP5Z3eJgB6xOuwOm7TizvyOYOyXa8nQQ/9\r\n5Q/1wgKOyKAGsvf5O+U+dc5LoV0fnNuPw16Kb2iZwwupZSNa6G7uxCl+hHhe\r\n2aJvSd0RT+J8/eky3RfdYX9RtSEw7VP91r5n53pKrWN1I1bxgX7yHj24meub\r\nbY8f1vh0dMNbA4mtGRwXZyEGwy/c9VyM+DI7s+XqQcNMozAUTzi3usb9VPrP\r\no8dBAk48VqavmO+EbzWAI1AWVDZ54LVCr+yvVPSg6l+wsTN9bUyoXhsMB6u/\r\nKI0OfAtT0wKXKEXR/Sc2Qj4KWj1hbnK3QxkdLM4yowxQBglSD8ePng7Cucl8\r\nk236Rl+x5EnrgVlcX9N4atyo1FAuKpQpz9IO0J/VXktNdjR6JHI0va68yOOR\r\n+djs0qG76tt+G66w+9B2/5sZPkZx2fWRI46AJ5dNDK0aZP1DdQUPkHv6MUmN\r\n1N3lrSgBK8pia53x3SVJvdL5rN/yJnMD/A4=\r\n=rh7B\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"030c14c03b78bfc981289d4d08bd92b91ae0b470","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.27.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1667786536916_1667786581818_0.3625200120188914","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1667786647779":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1667786647779","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1667786647779","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"1bb1921ea328010b49fc82df8ef40423b8c01cde","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1667786647779.tgz","fileCount":8,"integrity":"sha512-MfqJNu+JYHjWO2q2+pc849+tatHEFuyMmIeqokJxuwn63zaOrFYy4IdfXHUG1qfdLGI1dzswuwFwk/c5IIJS7Q==","signatures":[{"sig":"MEUCIQDbiV9D9K6OKOCpFEB04de+Yt2lM2Y3GXAZUuo+FvtzDAIge/jZlnpuzjgwOUgUZ/Phz97rSoc0wVcf8/hRURi/IpU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjaGfFACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrkdw//aVMSm2dwFlqtmPryloJ1zctp7r7byR6CTomS5GbW0Y/p70iz\r\nJVgrvB2Zaa6HcgkTB9VahCsjOcCbXb7JuXJzAbIQPRKIP97PJt+n6zgL5A42\r\nWeDM/WdHpX0nUKryxNjjM506X4JXZyxVehlCCB7mrcwXJVDJK5ozv1mjYR6X\r\nH6PdGchsWE832EpDGFAtyqjSrjCemyATDKYsD010p3cahl9CMWfX/lzT9+Ng\r\np9zxFRpmquS7POGGS+TG2CG7BAY96b+S+tv8zSMV4yRq4QGpvRv9BlwOKAHf\r\nk8Sd8s7rgo3ZoidIlRfFK/8nSOz2GbPXGW04P2plqy9mHmpOzhx+jXtIiTQg\r\npJP03+jrygfWDdDeQuotRIgnlqQqN9rS8aEd/O5PDOBNUH8MoRT1VCdxCi4t\r\n9C09d+jCLeytN9uIG7avFUJ83m/RPBRyYxZhHRkPEr4ocod3IqR+zTeC3ioG\r\nEqDOQAxDM4JRXBbJOlArKbvaMTY6duFMlGOhx40EXfjZCDWN2+zD8+xZ42VS\r\npLi4hl7CvAdnQFUdoHWEDT2AlBYVQrl5X47fnf+d39iZuXzYp7dhhR4G6+8u\r\nnLCeXsMEZop97d2DdtSuT1sKhINjDhqUfX6TzOc6Pr32edwoPS+P1AmJFumL\r\noHU+JuwU1SBNfP6D95nsHDKoKsQ3quZzs4Y=\r\n=AOMK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"554601d02d5f059d109182d21952837cb61d7eda","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.20","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1667786647779_1667786693500_0.18055094824771367","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1668391468215":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1668391468215","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1668391468215","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c97b1e1ee9eec876e8fc16b7ca73789970ab81f9","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1668391468215.tgz","fileCount":8,"integrity":"sha512-rtzwjAX00pOb8O2WVMMAGhipqxwvqnSQbeTCLv1EFsMfTxnH7gtVCW+yXRaziQEwC3+qxjKPznzYs1xZcFn0Rw==","signatures":[{"sig":"MEUCIQC11yqysPvvAXkAKQ+krUoRRFy4UTl0jeL+gwftP5aRHwIgbwH26BJIyE5fQguVW26Hd4dH+JoWEnHSHofLG2WIK1U=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjcaJgACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqmDg/6Ahf2ZVaOUXqEjSx9t6o2scOUx2qnOFkO8rIDmRoVfM/J498X\r\nMkO3rlq63te/RI89aj2nn42xCiRLYeNciA+ufYKfjPgLtPcIJbb1vnzLfGeu\r\n4NI+5Q2k9T+zbf80+H9cpzyqASATNCKfRiWS0DUK9BCXeGlTUKIxIqvZUlcv\r\neTQ1s0DJ2JwMeZmX1cpRF19rGHexPHlKfte7kXbKEuus9nQXn0egNC5B4Ehk\r\nZh5zf6CO+XtZr3XKZ6FsJg3rQAh2ymjrNi2AOFmFnh6P7nl/g1g5E+kNUpXi\r\n9k88a4HlkE4V9AMMPesGNmsJvLF3ql2Wmgg+iag09+ecnykETz0PgsXRysQZ\r\n6o7qvKXMfjn1WME8uvYZu35ZsDiNk1Lha/MT+ksy67TrBQEvq0YwdgMDqmTW\r\nOvergltQu2cm8rBCOynfeoCQJARrOf6qY6bMNYPTxL1OOm+53Aosor/UvN1D\r\nRYs3Z/K4ZHIykl5z6dxG0IKNicQqqfS3oUu6D16nAWqCTSNpIDiRdH6VPWsw\r\nSmZpkPHQHtJVoHs1BdWAtgdS8iq+lbjDDH1nL7yRA6Zm9dbQWnFJwhIVak3b\r\nyh7DDc60FwFHMIVXNlkrhGeODmsWzlDmCyFTZqD5ITJNxPzKMknPOobWfax1\r\nbLjbwr5bcDz7+Ny+goao3HaY0mrHRKBdCFA=\r\n=ncsO\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4be0cc4a408de0ab1357c2bf1fcdaa9b1354a05a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.21","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1668391468215_1668391520521_0.872872343330346","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1668996225529":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1668996225529","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1668996225529","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"8b8111bbc36ade2b65d6eb81e22a535eff0fcf2c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1668996225529.tgz","fileCount":8,"integrity":"sha512-og9lAKfxvYdud2nzA+JJLBC3lJZzuMbF56pyyAkuIFd8d3BmT3B5rnokYYVTF6CtT2VkVlyOajzN8lxaCPtBmw==","signatures":[{"sig":"MEUCIQChmzfqNIeGct47qzYl4uszodMgc5mwxiwaGHeMGT0HIwIgP1AIwKeNlmmds/2xhfZzAYtOjK3UF10Fk4oUQry9vCM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjetyvACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpuQA//Zx9AArI1Gn5XFHO1RrNfuZb+4d3zailV0YBIwDR7679sVfxR\r\n4homf3esN7xsnOzWSwEBVg+skSfFVTswdyk+NPTFYqxkqEck5Kwd7NwW2LkC\r\nrg/40OWpwEnATBxKmpjl7CEpdz22s2hO9O2aR75Uw7QtappuAakACySOP0pd\r\ntoLbv+YgsaKGel23oH3wP7YTZbmxesTpLAkW6W1XrxdTJs65rIsjor/USInf\r\nLiCkv/rctp8NDtd5AFhuZUzyClgTK7GhNdrYNJ4esrK//SleH62S6Jh/7DpU\r\n36D9vcr0XwkmHGkIWKYCdthDIHpqFQHwyXk5DaKE3ZoC9H2LTUqHwdAopG1T\r\nuuNtarXfs/Ke/1xyCqct7ngBt+MB9F7mjS7gefRN+M5VTqFuGsI0L0XN1b3Z\r\nAI6ZXIIav76GCwV6eEyb21R1EKXh92P+CqdSRti04OK6iTh9SzyoUPZPuC/H\r\nc4QcK+8cG9mcrUypj8miO/N8bVQiGhfxVRRgMo7TFF6zn0Yh+P0cNEYRIM0G\r\nAk70bnTwAg7cZmlxNerJE/CrmozbdpjFGYC1/OGLgjxePtpWWbArZYGyk6B8\r\nLqL1rgsvRMhoIqWSHobBa2v5F71FP/QGctPnb/WqSGJOnNRUxDRam/tvT2TD\r\nqUUCwp33ho1abyLWDYKU+V8ysKiL8p+aEgQ=\r\n=1p1f\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ceb6d454b737b3f41912c9808c08403c5f8fbb27","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.28.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1668996225529_1668996270930_0.14774972609416137","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1669601139738":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1669601139738","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1669601139738","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"5862356a98f6c6f342167acd251b5f0e078e2ec5","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1669601139738.tgz","fileCount":8,"integrity":"sha512-+vSkC68HoTj53CS7poi9Fl4yZSor1i2JWRTLzb4vs9Hfuj+Nf/aKa0FLF7d6zx276TfoAOk8vPq8xcpptpfLhA==","signatures":[{"sig":"MEUCIAwyzvRRZ47gFxfxSRYEEfkj2JWe5eJ+l3+THFZhg3HpAiEAx+ary+dwIM7etFOI6Wn51kLI9Gau6Pja90c5/FVDIZg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjhBemACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqNTQ/7Bb1XwlchIA+M5DWcHQDV05QG4TBK2x37QNzWmDlxC8Y0ASjO\r\njGb0OYywjcIez2OFWcg9FWu0bWsh4LG0ZjbS9Ye7Q4dXlkFhrFRE2kknh5SA\r\nqvq+8viUUzgk//7KrQAboz9pY+Vd78oDHjn64Iu0FoUzGZ/qCg1u7aF5fnah\r\n4xzBr+JvLlmchkZdH3Pn6MeFe3HZ7xsq6maJIN7FdSYkBknfLPuUkpSp2VXC\r\nFFGNj5XdchinHeBkYv6pTM3R5PhL1bURJPRZEBlDqkAhRuryFDRRGV44z0J4\r\nqxFwfF+In8viCdwWoUfW03mp9qP7xCWQmU8tvSN86Kq6x9sFE0MCta5yknlM\r\nJnixrKVAYwGzRMryUM/JbpanAxcFQmNxgbMo+WUfdWMecHqpNYtRHW7/Casw\r\npnc9hIOUpYKSKRqm23ybZvHejQxM1p1eY1D+YtLTFS7CY1tt8sni3Yo7vtf6\r\nksOcFy/BuV2EsESyI9oonvJTk4gC7q3hHPMU8tVhUHS2meyjyDxDha0fYcOF\r\nlQGj1ltKtBIqmAPm6KP6MyP1DLEM/kR50Rft/MM5N+Ew2Mm1ZLFtfMOwdWqQ\r\nUTN1XauPuH/lhWdGP8ytdKxHgcBx0oC1944Ce+0whZ9VpRLYzS6qKg8beSVq\r\n5X4QVZGABez6KfpKYLTDCOlFLE9Ol2yKY/4=\r\n=30rY\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"c8924cb48b7ced9f7ed6e2ad612c2b2111148bb8","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^23.0.3","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1669601139738_1669601190405_0.40797320566572126","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1670205972153":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1670205972153","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1670205972153","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"87ed3ec5c537446458aae534647974e011fc818c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1670205972153.tgz","fileCount":8,"integrity":"sha512-XstLlWOp0rsGkNuJ9WLY7fbfU93ffhAQJWzG/JHFjUPF3J3ccu9RQ2hGfapM8udVdzxR49U6a/L/2s7mNzxFbg==","signatures":[{"sig":"MEYCIQDrfohIZ7PyKlVVtd5cxSgKkqdwas6obUyZf2+t+FLjqQIhAKSVJmsKoQo/aug07GN6/AdG1jwLh29homJoLBYXbvRK","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjjVJAACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpMKw/+MF9O4LalRVVG2Md7s21P2tZUKRIN1+llTC+B6OCXsfAFjrKg\r\nORS9weKLHlJvrrVgMQ7BElCTUsDU6zSlCjijChH+L24yVsrFr1djSMAovCQv\r\nV8MzEKMiG++uVS3nH2aC098cM3JJtzQrl82kNxSrsqTtsCye2E7hOl3kAzVR\r\njsgIPE1PD3KkVVpgQDPjB3PFCEyr8tV3K29GyHqXgd4EYVZhJEe8bV+7bApN\r\nCc0FS1uxLYH0Af8ShZ/3VoiP5y8V/IEQpjJRu/7n+UzJXU3SmxOu4aFXTxjR\r\nXHCWT8vY1jqzHS2XCTSvV/VU9W9ppNp+MZPl/0qNrbtP0QAAaWU8E0ANdHwB\r\nblnG4sskB0MMZypIGlLHbqcDx+LCkTaEWkd95PHyTZBWOEoM3PtjL+6PYnHB\r\nMZEh27vovbHKkU3Omj58DU/lpwNHQYkXudRX1kYvV8l30jyHyMSre20s2Omc\r\naJvsEQTf4gIYCATYLwZFTfiRPaJMAS8ailAJT43womSmiM5VsdkMsER76AbX\r\nnrxOQugT59OqG8/wmVg9HH/lq2Khd6HssOPyPvJPj0P1eqtRI8yM08fRlhz0\r\n3u6PRqfLHROgfPmTThOB103PiAzUh1QW3/fB3+2bntGWTxfX5t82dHEckg7X\r\nAvYX7vBNcL7Eb1cRZOJk/FXsG4+AZE8UTXo=\r\n=5eBe\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"7e85693ea7666862280c30500e1df575b2287fb9","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.29.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1670205972153_1670206016555_0.7775570095513684","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1670319096136":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1670319096136","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1670319096136","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"89da09894180d9d2004eb5343d8519a97637314d","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1670319096136.tgz","fileCount":8,"integrity":"sha512-uDuaeV6EDmm+VkyYcPMpQl12CuiQVkGxhLyNnDmauP5RskAXAmOQxIv6FddMIo6T83l8xBVh89+7ZStzCCrGxQ==","signatures":[{"sig":"MEQCIHW3811OY3d3lw1y+fGUnwfjWVOrO47lrfK/zd0FISXsAiBHOmjtegAm2Pm9zBx1SHwuyw4HBFOM5fSSaimjUcspaw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjjwwjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpvSQ//Ur2iMyVhg3m2md8NtGXuCPSqB8RfPmGGp0zhA0SDRKTKhsCA\r\nm5OKRhVzRHqTRy8qtS/05QqkZRxFq78bE2wQyHN1cHhhTrqTuHPdPKDO9b90\r\nbOQ/GteG4nbzS6Qa2phItGFSwEvxVumeN51iA6yAFlOGMmYp+Tq3zWJrbJ5O\r\n5pF9jGF7oTiY2JWsUu3ymOq8YilgApKYjdW8kuoGaJR/45e8zYbMCwUDYZZo\r\n1xnwXOJ2MBlCneZqbKnq+oWDbdEuAd3whQ+UT0lZmSS3wUomJKchR5qSbL0r\r\napxI1u1Txgh2wNEp1LIkQQ5aEmJxEehu4bqRM34uy6gSOhHLsHUYcnA+uvya\r\nXV8I1laejrucsK59JzqgGzPU+MD7oiF/S5MUM5KM2YrAGK+FaGcY+sLqtdnd\r\n0ej+SidnQJnUawPkZvOMEWYFXm8myL1oT99HoAUuh/btQj/YBZyDaartCEmG\r\n6L00EoCzZyT8iPGPQz/CB2ShMf+U4nCUxV8mvdiuh+tXQGJ5DY3Aws12pz6G\r\npo9bn12fuHbBfEdiGlzAQrHacZW93yXAdK8JMT9uSe8W5BILSo/XcM7Um06p\r\n4YsHz7vZUwFID4wSNvGEAyJen0ZG/owxiAc6+qmMcdeAxPxGD9laD8UfBkNo\r\nq6U+xuhCzmpq+WqvSAOjb20agrhA1Y+qsfk=\r\n=Em6j\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"f0f0780b3df4ff985d5b036644a0a1929d343b08","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1670319096136_1670319139502_0.7695646138021282","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1670464891557":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1670464891557","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1670464891557","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"008ac59acfff7deb5ed6429c17eaf4fafe8c8488","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1670464891557.tgz","fileCount":8,"integrity":"sha512-G+T2HZ0+yk0xCKcIui656zQO+k8yhAOvl9SJEViTO530srt8RYc6q7QxFVS4ATDo1a/+YdITVJ7M1VGt9FrSQg==","signatures":[{"sig":"MEUCIENNGHkO/NFDMZcsFFyELD46sHOVy7czpckFDHeDgM5wAiEAlCzIhd+ZOx6Ea/Pr22cUywgTzt4YtXxFeTK51fk4LU8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjkUW5ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrHxw/+OL+FQiway2Kf2g11GPxtutqCmEnY+9YGMXbAGLIxK+TM7B8B\r\nW2RSoExH2mPFjYkEM+SDtqpcJjTPPfq0nQR1fU0vbI9Xrw4JE2VyrGbOnWD9\r\namQSVXJ6owZRFGiuDyCE34/lKikmsHK+WC6QsFMlO3sVKU1qJ7a4ISrmr06l\r\nGGKCNzHaIN9yj/jgAc7gaNnBmfNX1cywhhOnXSIJ1WENTfqPIpfi/iPYUUoC\r\nkHbgKCxxC0SIMDfY/pHzmyK0J3luZoEQOKdgAKX46+X/KJ5TLxzZ9vnmRhRg\r\n9mUwKzGtCXtk+tLdIWFBMECyZA2y/vYD/K/ZouN79QYi5Jh6vXN1TqxEj1GF\r\nGkMlI9WlUb6qvpKGRIMqi18FcJaHMTUjcVlWJBWyrX6FAkhS00CfFj6UXOKs\r\nqhnIW6H/8o7MCTVMAMzM6Wfl/qmD7V1wfRLhNtVhgFPObdOgqYp0Hlqvc2MG\r\nrvB3y0PtqhmaoLQHKnc5bfWlfVQx7U7W+IkA5bgdZD6PpmGJBzwA2WZL/oQU\r\nn6OoYmldPzPUmxPH36DGIeqtijW2dKICkVj/hnIaWzHsqT/33SmjTnnacEu1\r\ndRVhczlkEr7FRjRXhfULU0fYXxGHt1VrVCG1abhNct/QhNiRDfMfEoSBF4Ag\r\nmBsy1GPP89m1vq49OmNspTd6ac59SmFQ/LY=\r\n=gPJX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"df827e4c67cb9e546d5a1eaa930e2cf687bc0b9e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^23.0.4","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1670464891557_1670464952950_0.9550273039664148","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1670755820150":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1670755820150","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1670755820150","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"c90089d6fd851034dcd2d88dac22377317a56ff8","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1670755820150.tgz","fileCount":8,"integrity":"sha512-DLGD2X06AB8DHj4Y7AiritGTUg3cU6c0CW92dF2p+JqkHTFYBvGpkm/96L6gDNANlA9ytVwhJOH/M+PVMEdkBA==","signatures":[{"sig":"MEYCIQD1ihKtBwOcS/LW/f3I1Jg/62pjphApXjOcyKCrxQmdGgIhAMD1QI/O3EFXacJcduy+PsdE/n8NbwefYTaCIaisCg31","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjlbYdACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmphiBAAjKFTotrKCr81f7zQQZ4rVw6roQAEq6G6lW0Yil/rnN0QRsJi\r\n8z7Gg56WQKGdm4r3uuEu6o6cFqyezfLY7tK8rj04EdUjEVCoImV/kSIzBuZf\r\n9ysLBYihsAQbJjjzPm+B9ri7JY5BgJIZYUQF+r2BDB2Z7TD15SV0E+V5VOSN\r\nsP5M5S1phDCXrmG8JgkpJpNKmOiiK21B/aU2nIiG+Q1VJ6XcNGy48OfQovXm\r\n7DzO9nGsxUMWR8NK6cWH5xJDG7X+w9dNmPzMni3IoDV6ut0a52kwHu8pQjYt\r\nTx36RjgeTjzaAljTde0ejzZhh5z9TqxYUKXngQN42nt23QH8V1UixL7ALkVP\r\nz22cf4KdKKICLMm5kfvpCCLufMwD/3p8Xm7lL0S7vZPaAtC6tXYMA9cXjV6L\r\nHklR2l+6gxduqVconSPtFuTGbmz8Wvzn3BdWUgZivEZrIvtTA3QTXrI9lb13\r\nwzChqzYN3YNvwKYWwRMachtkbP6McDmwW+JjSabokvid/wMlIGrFhbFRTpJv\r\nwBPZGPia8UhmrrbgHP31yZlz92noTb610CtxNzRtj23TFVZnaMR6+6nIgWYT\r\ncPZBmz2mstVqetA4bM5BpapAPvVU6VD7LREQ3jpCURkSqfuS9wRFe61suyh8\r\n79+IO2ILei6JxFJzKuGiRLaLkvozDfsjQCQ=\r\n=7YDS\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"dc05c948e8406409a852110c74cfef91c461f307","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1670755820150_1670755869113_0.23242403648847598","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1670810566504":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1670810566504","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1670810566504","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"cdf6ec78a1e8928e3105009c1d1e42cb84a61df0","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1670810566504.tgz","fileCount":8,"integrity":"sha512-km2wbGxs/Jb4KnssuWSgUP2WXsxFkwkupQLoVn6acuMX1pX1Hce/E5WPk+/pfgXUvU8vl2Ns1z6z91JtxTdW+g==","signatures":[{"sig":"MEYCIQDXyp039xTWdrXa2nXBZOtuno2Jlk67eE5EKX/vo9BrgAIhAKXQ/O8zIKPdX/7SeQaWft3nYzP2Bn3i9CC0OiOhuxq5","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59613,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjlov8ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoDog//RZ7WYp3qndNe8pU2C/7dP1/RbNC5aZg/8SZ1FdJy2cEzeFNb\r\nRONk1fNAsYHWG7Xf4d6zjcw7UWOVX+UufPHCJ5z0HISX1YnfLpePXYYz216u\r\nQW0vlcqIgHkK1nCnJAy4kdod5F3Xc1GJ6vbyv4hz+HLNTT5Ycn/eD7MBnWvR\r\npiY9Bwz4aDDGCOv3HRmPMk35jb273N0S4hSE52GX45To0CvAnOhW3PAaIwYM\r\nLDqLjYTL92agDJG9nERWX6n8tZbKSrJ1d4ZZk7OQU969XLo0T8JrD5Lq7o9v\r\nSDDk7c+OgY41B6xi6rw7tLGMGLe/fcmvDvjf47XK6wIuyPqSJVz++HcUrgRH\r\n/+uit/U/dVDteq04x9y+MV4YhizjzUYeuinjqehu1933vrH8pgkoECXNMesl\r\nOsUf2ATkfGI3Nd6J9GfVag/f1oYmEegEiPQpUDXns76uyuOJ21DVUvkJsc0j\r\nErE4Bb9UfDgBGYKwLCotifioxpxDJB6U9BT0fF5d/TMQL577cQK8V5UJToqd\r\njE6+p+SwrADewm3D+Ik3rAmESjtnxIhXAA8TH0xY+fgdUTlcumUWNyJj40Uc\r\nD1W5MM/03PCu15BV6muWZF5+c2exQn2DrvzTHa8OqgzPvBv761rtiYTAOZFL\r\niisnebCwEMM0KYboiWHl9dKnYrX2cqyA5o8=\r\n=dH6s\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"12975037a37f9a040be1b7f725bb87aab10eb5a2","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.22","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1670810566504_1670810620658_0.7847824777401247","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1671156059279":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1671156059279","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1671156059279","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"59158700c5df00dc361ed9a816039cddc1d1a721","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1671156059279.tgz","fileCount":8,"integrity":"sha512-GO7YapSurRcNEdwljKyzCwNZVFd3wPT7r68BM5RMMUN6rnM998nG1zMC7jhVqJ2XdH4pwI1pFPF4dnm0X16e5w==","signatures":[{"sig":"MEYCIQD1QpxKG32DYKe1HaJqtHRQHjLF2cJUBONeyRN0AvcdlQIhANhQzMbBTmX/L4w/bCakutDZ/QyRTdV/i3P0MugUkcf+","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjm9GIACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo3UQ/9Fs9MB98DO/gFaUdLL/gDq7pNt/UYKlfEhpHa3LcdN9PEgQ4G\r\nYEjo9Mf5wmGNPxQM5MSlhYXMRJbY+E5jj6dw8/YOfi/Nn/BFbI65BZOgC/BZ\r\nZ6evXNzMFLZYGUedU0tXirnw9YCNlvBGj02CgHd3EGd0NfC61WxLVARDUZuG\r\nEWHhiX/rQ4sjQMtcUOtdQwU5xAldSey6BhIkpe457CaCJjg+kjvUQig5PjsQ\r\n4Rw/o4o3mp0HwC6mpOXv6SsioJAnIMjE6Z5Tug1dwNoEP9TOzQugfN0qC7Iq\r\n0cL6dkwKJt3A768t8WaQ0kuJi+TfyvMCy1QZF76L3cYggPgwp8mOdeiKa4sn\r\nvjbkB/IGOi7rLGvTBs//VYis6h1rPAPYs/veG1mDLcYvwTXV5FLqfCOCgtCA\r\nhZs6QfBVVZHXcAALT0ptG6MPC8+6qu8xIwHRaUYAWP4ECdSyM5L2NWD2BOVf\r\nO+LjdSmO5EH/QAbweHQ8OqbZiRU+4xaiCAaHHFLdQGBeBzLrThmP4PkNoV/C\r\nxQfk7YU4ZnMr/qAAoQwn9GuwfatKpNrrN7lNcxPL6jLf9yFYN70FhIvh7bP+\r\nIFAVQBmzd9KxTlPwIFOkWUIfLEz7Wd/X4Z+t82gsVq2xrDOZRQXpFg+0OV/r\r\n+LtdBYQw+ghvRBtFibZeLGtkMJN0zO9XaZU=\r\n=foXQ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"ac57db8befadeb2c4906b95d3e412039fd2715fa","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^23.0.5","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1671156059279_1671156103889_0.24751293154025955","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1671415306995":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1671415306995","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1671415306995","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"f98236026e0422b36029a980ee2dc12d4a2964e3","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1671415306995.tgz","fileCount":8,"integrity":"sha512-kMvVyBLik/6QHoP20lmSdBKWOiNzNrxfRXUepu2iPmFcIEQaEo5o4sOXsLnf9RIiMdDyepkWMa2LR23yAH9www==","signatures":[{"sig":"MEQCIDPjBNB+X5SllBLhCwxRNFOe6Mepje3Oaa5+6Q3Ef+ABAiBaNRJCUUfyl9DxJNygKySdmsFH1JM11OPcRtpc1OT8Gw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59613,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjn8ZCACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrEKA//SPqkmZamwwqcnjs8sjTKossf2PkyIDI5nvVOrqEAuFkm7BNO\r\npoK5ny4+4vqzx+IdTXCcZVmDV7nnYVa78CufAeQUw8EWxlspDVqRmpirVOzZ\r\nMFfW8PXREIC3meSbrgrERlKFqwQDjkO330iMQQ1PkkTbso2ZMlZ3CyLlo+ck\r\nocTDcj7fpgRHp/vxMUl7itbPMDhuzv9ppUdKtNLRSg4h5kqkOwEr3E5tygrH\r\nTMrwSlvhItmrAZZdsoJatd8nTccodW3SojUAnl1JjXGNHNXWnVEnA7+Pa24/\r\n/Cw34H8aGoDeS7oWWQnjCNjyJOcTJDyuF3ALKVQU4Y4/FyPjVm89Qpb58i8r\r\nodI9LBRJNUxPYbj6zkn1nbB8ERgYm03+TA90Q21dcuih33N1Jw3mltllA+JR\r\nmTzmIsZcMqz75CMJ6PsAviYpORiNqhBvpoLlvznh8PIdDRAAgE4vmt27P6y0\r\nYO8Rax0FgZuhDq8CrKFlpFr9/slBML/2J5/AUSUNyOZsIBnIKErbYRv7UWmj\r\nuGB6S8/UwiaR5L5scyZxL7WWUhkXFZ6DUjQ3sIPMhlNnPq+eWBRPoC38t89g\r\n7rZR0p1CD4YHqZKN09a0oxG44spCFhXw1HaGcEJp9kkKo8Ee2PYslvSm1em0\r\nScl5Am8H/BvYsjwjJY/v/F7RH8UuGbwijIU=\r\n=jYri\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"790b674dc3dc881f5f66efed7a8f4aa69715ffc5","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.23","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1671415306995_1671415362061_0.18867854933986128","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1671415353243":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1671415353243","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1671415353243","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"01646c5a26229bab36f03cfe2a803d163b255f16","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1671415353243.tgz","fileCount":8,"integrity":"sha512-ehJ3lEWHJJfT8SZgXBpRwtiwn78yg0TOIud7I8OKmm5jm/UwzubDGZUn0pby5cmefg4mMOdD1Y4S1Dn5QvpyfQ==","signatures":[{"sig":"MEUCIQDHzJINHbb6CPapag3PMc+PJLz0amN1bK3Ny2W8ofhevgIgf+AI0cfdFDAOQyuS1vascDHRiKvKjsrhOckUpCkDCvs=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjn8Z5ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo+LhAAoc/8lnMUkp1VGltr9QrtgDb3GeOOuegWI0Seu/FTkFrhAVfb\r\na0QQBq/CIMMsAm1l48K49JFFMa6huENpzXfW76xnaFMCvlnD3ueK9e4A5Y0F\r\ndxTqx9YJJsIh+7Fn8RkLzhE7t8FdUaj/pTjdJPaTuf3+50gMg2r7w3oJJTF7\r\nip3WCnTYe5Axb9sRdHusWOLGl8khhm10H4yZ0BY9ncNAhQZ3b3107QndkFhZ\r\nd0feiTFTGbHNuq67t0caxOxdkt7rqbmKfrHpnAeYIEB2G0Z+pz6ehPNVyCfc\r\nstmnlfdaJBfXgqqsXhEsJqGTwN8+7OR2C/Pj1ySLwrtpEWo7CbbwLj8J7eJn\r\nL1EZULiwgO+fhK7kg7JvTkPAOPOF8cfnQdJP4afo4pIfkUlJekoa7Oj5+W/7\r\n1k3uwWv+v6doZMnsx2fy1j3qLXCv1KXtzXYlxBBSRB9jcgpFPzRRSxWqjwMJ\r\njpIM+BxHvnsJCH6sRZvnA2xiHfeM8HnEILJ4ADq02MDJKgy2ztiLsbgW5kPa\r\ny8qqmHVGkUxWMclXp7zQGfycuq33L5buKcNFv8aGb3ctlQBNA1hI/JYeLxDO\r\nB8wFNHrlYsvpsEvWnfLqEsGrWX788BQq0Y8R+bjUi9Z19KFGO0aw1FmdUXYt\r\nqJICTnjC/FLycXi0RT9rwD3DAFk62UhqMfg=\r\n=izlK\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"80af4f6835964aca544f635cf55b9a668e672b45","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.30.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1671415353243_1671415416834_0.43972722368301964","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1671415397506":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1671415397506","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1671415397506","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"45fc65cbfb581e5bf0345bcd97806737ac7b8d53","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1671415397506.tgz","fileCount":8,"integrity":"sha512-SlEfdnTgNruKGD6heSgM3BmP/ImM+NJpWdfCoE4pB6/KbHjxwEaJMla4vP3Slxo1uEN+RtQk18eqDFhsGPmo9Q==","signatures":[{"sig":"MEQCIE0hmz3rK8B1lQFYp2mCCNIPRWdyyq5Sym/AUOgRC8fEAiB2SaExCp4Bv6xNv2OCn8zVp1wwGFpBVYNvvSce9TT7Aw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjn8aUACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmofphAAmQIqts3Ir6t2L4D6WmTJ2oamDwdTAcPCJ5Swk+Fa1TPlIDk9\r\nCOJvzbcGlsGFA+B64SU9So/Fw+RDilr4IXmDIc6FcXnAtD79qWrEaY6romKZ\r\nZvtPvkzsZWX9XYWxV/QRKN59VAnqh1T2JRDyFvXmfMSAO//Q1iPFaRs186th\r\nzPbPxoHZA/V/PUNLlLMm2ysU8JSlUX+8IIYv7A9prsKm1z1SGBngN0JLIEQ/\r\npBTB1zh/cDWX8sOeSo/hL1DxQw5xXfYkBPyk7gczO5+M7J+lJAJENjWxYdL+\r\nMhF7vuuMTXJ9mofGxs1cElQ96qkOQtBgjkXdQd2ncrHPRs6QafFSo8g67VHJ\r\nN1XeDTviF+f/+3cZVUv1x8s53DkbCXuP1QI1NXC7mecKRbCxD6m1F3wXYaSN\r\n/1uA6z6A6r2s3szIS2NOej2jEaEZkCm6pJe0+aF61sXZDH8tIMo5P45w6HH/\r\nfqK5dx+bnJZ1DCJ+BPqGBayL426YxIZaR+yV9zbBWW1Qtqfa/dhnLJdQFxSZ\r\nSDW5dBRQZA6sYTTPPjbeOqgWDth1g3DIZy/4cZuHKPyW8fGK7RWeCQJIE7H9\r\ni6geFAX1GITsb2aKx1/vzrGses5N05BIHRKBPyac2UA1e97va23ghNorrOg+\r\nuJQNPxUP0bxbQKO7M9KZMZ6O0Y/I63jhGAM=\r\n=2Nbn\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"375a27761912313869085024cbc1dbd1048fe64c","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^24.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1671415397506_1671415444719_0.35649815720720524","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1672606645423":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1672606645423","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1672606645423","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"86cf89cfd647a3fbdaecff64ce02f02d709c8ed1","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1672606645423.tgz","fileCount":8,"integrity":"sha512-Rgj/E72WEAAMA3JyqJ0IkSWKX+1vOc2I4coR2RjSEk9my1yIVGkSVPLFG9eRor5KTyoCJVZw49GPPmjasEx4rg==","signatures":[{"sig":"MEQCIFlMDtN2qjNu0CB0yaZOpk2pq7WJTBvxJM+EV7b6bFZAAiBv1i1csrbBZdpCI2N3HCPyoAMETAIH8W2nDd95Mb8c9A==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjsfPiACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrzwQ/+I8VxLzrEWMNW+c5T1g4XMI6fjRs5T4bmPGky4sSKACONcadw\r\ntCGvK0UpxvktyX6rh1CNGL+RueEXC7PjoSG6aQIw2r1hzrh8nROe1jKtEExY\r\nRb/nPJsVRkUkRgCNG/or7i0dUqaDYT8IG5Av/2SYW6W+ieH6JkD3joJLDwsB\r\nsSQO6uDhQeAkcoW/hxbgI9EsuAxcvD/SQqfXftmCLOMZKUMTRnidXAc6uPWI\r\njXV87+FVFA3nRsAS7aWrS3ygkAx3Gxh4vOC5QUxV/02c8yu7e4Oohf3ozabM\r\nOe0oNvzN5CN4dDCe06K4G/sOGXY87SRKzSa3oJ5vgwFHOty6M44Rce6R/VSZ\r\nVWqJ+0WoD9SFRv7+UKUPPY4LonlvoBm62MNa7R1KVtA9Mu8REZbz4oshL614\r\n2hhAZm1qr6PSCN9gbRICuN+y7GYtcZG8sbIXp1WWBG3SkZ81AIYzy/zNFjVa\r\njpP2pf84paD9zKKPKWx/8+PxKBCuRIdL0yb+mWCadQpKiF2PiJ2nj/GD9BD1\r\nB9XSTGw/j8VP9kOhQlRjVwktqQYX4ex90v4JTiRWdbaxWxp8RZLRvCJXfvT6\r\nWFBGEtmvjS3vkCAnmD7iebNkAUgL2I3GxJBJ5hligLjhkWooq7mKfqDWClkK\r\nEtd4b+ZzUNqP9+PQMkEQXy41znQYkzGnv2I=\r\n=pzT9\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"e346dd1819ad53d939e22d336949f6e2423ef015","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1672606645423_1672606690218_0.9929384417344482","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1672624951306":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1672624951306","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1672624951306","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"2b8abb93e554250415b7ebfcdec927bb20bdf585","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1672624951306.tgz","fileCount":8,"integrity":"sha512-JIe0YgvYSEDkxjPVDjO8esF/yHbluLz9jHVKJJY+gFwBUxmy1fnTbI2s16QRIv5k2FyIjwF6xB0fvn9zcap1iw==","signatures":[{"sig":"MEYCIQDo4Tjcwp2l0GfwFBRlFqQmq1EbIx2ErMOztWkEHAqetAIhAIqcoAnGKRmkso0sfoPCkPyLA52DNaNj7mfVjZLb0FZf","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjsjtlACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq8zBAAiEBPdjspfaC5qGWsjivlZQrhXILuCeF2DrHMO091LtrySYFF\r\nYjjMoq8bLk3Vkw4zWZdZ7LJoeUO4bm09BVgKSb5G0hpHdfxzAzZag2ruTMSX\r\nyc55FBetHrXyO7DWCH6wVpjUl0I5kJT4OmZUR2k9qjqFy7+FI9ma0/IkI6a9\r\nCfq2wDvoB8smxMmwG0KlC1cTWCViD77PJDSihyb9nqub2S3RUaD3N9GmDbsF\r\nm9fVpBO5CmpWcUj+RI5c/SDKn4Jag2Pse5czkJUiNhXshTuKx4aRpyjo3eDf\r\nPgMMHCA/6zydWNGDLolaAShL6G20/wM7Mw4x0lrH1Pr4c//0apTyNEiz9Y1g\r\nsdLoDmFcOncx6l49rg+k58d7OgksNr5EjIcw0NZOFcFTVhj3wkASL6MEZkze\r\nZY3W6C+4waUTNaVFkT9tiopoMNFhhI8JmDiJ+8cPX2dNaYPP4ZpJehDZp57Z\r\nZElSdI0PjFg3PPAWtsHqrCkZ3FrlA2RQr4FrrZ2lHCEi9yMGcYiVUNsK5lep\r\nkZsQ0Wl5IrmGR2YchBVGJTQVCtwFwsqKSmJZ6O0v7VNl0SsB/bvWxL98zFoF\r\nYkueIewUXMDiMyPVthMglHaJZopjUS7osI9CXMbXZ/McW/e3aXJuQMGnTW6u\r\nJumQwTeJWwaBD8Nc3Yv936VuUxnnlcUF8+E=\r\n=dO25\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"9e05225a88912438f18086241bd7cfbd98bfdd3a","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.31.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1672624951306_1672624997373_0.7057436169475013","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1673119159310":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1673119159310","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1673119159310","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"3ee7844c34a4fb8e11b58bc6e47a194366c0e147","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1673119159310.tgz","fileCount":8,"integrity":"sha512-ipClnaM/Z6Ko/F0g5yiOWnb+v75A0E/YrBrabqGAgpa2tF1TcY6LMBian6qGnCxnix50qzNsNkQcHeEVrlfNhQ==","signatures":[{"sig":"MEYCIQDqDeV1ZOxZiq+o+6uV7dZzubeSUktdbkDbOUDM4t6KKAIhAIAw27cNfPlNz1yS8I0ejt/RAfZezAOBzQ2YnaWACW2C","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjucXuACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpCjRAAmMh6ediWzGnUr9ZgAKzrfLn2TryLWHM6JCH/L0ofUxcZOW5R\r\n4q1EeqNBKmbwfhg9sATrUuwxWQyxuNzLBt2P1pCjZ93prlFXvzV6qFbtGS1v\r\nYX3kFcmYiISI30KUhZhK9WaCqmHNibUdVcIfi/+1yaF9QLFZVNPXgRSH3gxJ\r\nA/EOtOHiWTCk+t88xUJsEf48bFa5/dW8gFRourQtECi25u2Qc1jsOH88F5Ew\r\nisdvoHan9RzaBhP8e5VJML+KBCTRbn3DX8/+v+Sh+wj53TU5tXcB3cNAX3OE\r\np9lTRsfB62d9cEBgdh7Z42eqzeNPc4Wb31agClpkt8/38PIrFX4vBKYzfElU\r\nKc/cJyq9qxoxHrUwXlYkRoaAjt47Ev7ZliIOpenxJg/KsPTBNZv26inVhkEE\r\nRDrpHmIMeyWg5ZyILTaGoVrOxSGA7572a6FL5vY0AqNaEJWBj5mIcwx4VEq3\r\nNwyIUFsvQEZUliUVOrCXMl1CD8mLmts2dmox/10gHHarV1oyNuApFVD0iM7j\r\nU7yT1us0YG9Kqcux6+x7hkPue611E8/sCpsnMezsgJ0lxBbc9abgvVzV8za5\r\ndV3X3aEng4ONx6iC6jb/dOOEF7oPElNnsdF0kixd2sMmdohRLANhrn8Z6Kov\r\nmW+5h6TtPsDGMG+bDNLs6MFGA/I/XB94Vqo=\r\n=NwXg\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"333b8b2b948d391c69d1675aeea1e203f5f81dc8","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1673119159310_1673119214730_0.8043858761711433","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1673229859074":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1673229859074","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1673229859074","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"d37a5458e8e42bb3cb66109e034ca1418ce6e743","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1673229859074.tgz","fileCount":8,"integrity":"sha512-ZBnqHN0UXZYcUa97HDcgF4RqGpgFpo6mLKXjPVSnB5eS5VP/su+xDtUAV7TW8fOVvOfiQjQX6Dr6YfnLFdHbpg==","signatures":[{"sig":"MEYCIQDastm54SDTQtXfgqkX2Nz6ZtU/SmaUxwvnsxnuxDG6/gIhAO1ZmeexQPqTIhMVI8wGvdZL+KgQdxjyuPyTHu90vcHz","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59613,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJju3ZRACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpW0g//Whq7wVNUEjslvEYbJZwrBZ1mA6LqmqRrH910Mb54DV2fT74M\r\n7YbWq9J5AvaXgf81Ke+82n0cpk42EKIGkRgFiEcHZkvDUaHKv82THlMJtrxc\r\nRXa7qZV3SiD2ZAYfoVq4kIyeqnQkL9mtq4ZWad00ZDn7ITCA6MXF+Mj0Xqn/\r\nPQMeHuMwVNco0n/b5fanXOQ8OfVSXg7onmzkb7BvY/RWHM4vJZ6R5ELylEUg\r\ncvI1hqXXxoL69/fF5FpSQ+XyqvxNhC/jrc7juh7p7qUgoLmjYMy9aB/+Z2LT\r\nk/kQlr9yBP7VWxJ0lGoQhNg/C2Ocpgz04nnZmNWyay3l1lZfrvLRK3DpnC/R\r\n0eVOnTevXUoGKCVU/bup1z2w7ZBd6qJaXP6wBY8HN4qYosEnvPeHujctyFtN\r\nlj5nnLtEh88ZxB8mVGaVY3LnF9u9aMCqzqxiwXXOKFrwHn2g/yemd41u9z/M\r\n4tv47hYHIoO4PjfGRT+lhY6EOOfI0TCsAj5gMzcYguXbdUYg3Mtf+Acn6Q5b\r\npycb4weNFG4LDs3W/0OcJLVzMP92nshnrC74fCr7wIy2Q26sFQMMyswhXHXe\r\nkrxs9kEcLmq6E1aVcmqM9gTjdA+RwQYMmOAgCmMG4BMCnus//qyrRzlnpbTU\r\nDa9/ZgtxEtAwkZ6MsDDyd/aJWQm12QkEFF0=\r\n=DAjM\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"629f2cbbc61e643a4eb6431d7dabba977ad6c18e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.24","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1673229859074_1673229905545_0.16214794040534897","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1673836041330":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1673836041330","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1673836041330","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"859e8c43a5a1c443f6528cfc9d27b61e70638642","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1673836041330.tgz","fileCount":8,"integrity":"sha512-PkEtEb3EuxyOTK00SSfQUj1hJ87nluslW2CGn9lpxP14QSD+ZJsiuvJe/D9YrRIrllRqLIlH+yaw4tmSqSGBZA==","signatures":[{"sig":"MEYCIQDMnZ5N9LWpR5BET/zEpYQbJ8vHBzOqLK7Vo57fiokQwwIhAOiRUOvK5oO7//pLZdPR8SvqeTlq5Sk6ldnmxtkQ7P8s","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjxLZCACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpwfA/+IeJoDdqbBU52oKVpEPvFt9sG2+cdBLCN1BT+N6tj1QrhtjhC\r\ntKT5giuruz4Gcn5//FKByc27xoJodsKsrE+FhvZhT51Y0gMOetziUrWKVEZ5\r\nFXnxfuovDJ+p7AOuyN3fMf2FtSwPh2+eIkfw06vVlbBPhPWcu/Q/PGswK7K1\r\nANNfVNvUu6Cg7z0h9AykYaMympPWVhGm9q2vuMYtzBlNKWoZVGQwytR7ZHpP\r\nMSNl6MF/4mnrOMc+2keJdXvyG6MJV6SkwStT4I9TvZ0e/xIkHleH0ZfPRpQ/\r\nGpwfXCYYnHATC+kOUcA5V8fy3NvWu3iUKRaxnV8tNG8DpJi3ngEl2CMZARBu\r\nFyTH3kYbi+HRLj0kmO/VL0vB4yJP19baXU0cauzywFbpw0l0WYFw+nazZEpH\r\nVSznpocAU2jSToQL6QH9dGhFkDbqqFY0ITX5qDPN/8N3RQ2hf4ZXg1kdw/oG\r\nzYSV/soVIQAcHeD5OX0n0BOMId0bSKovkgX8AHPY5GT4manJ3Ufh2cUmG8LD\r\n/JxvMguJqLCIRdwuzbEdXaB8zKkM8zZp3dnspt1iHl6+2GZ2Izo6KIOsIVrX\r\nGoXfjELZ9QiQJuxk5bc8WFq7sSAScQX06aVW+3ueYjw8nYffrOhVnDeBugFu\r\n8nnVJ9DNSqdA9CofbqII10pjhfErK2KRt1A=\r\n=QI2i\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2778c44862c64b50278e64fe017a7cfbf77cacfc","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.32.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1673836041330_1673836098122_0.5066384933442807","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1674441891652":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1674441891652","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1674441891652","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"eaedaa01df7173c3d797da5c2e4f0c5924ec9402","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1674441891652.tgz","fileCount":8,"integrity":"sha512-ReTCBlfl+yN6m10a4fR59msWA+EF8zr2N0pXGummQDLd1Etq3CPiYAyF+gY1nrslaYxbQMSHTTGpmSMWYNCXbA==","signatures":[{"sig":"MEQCIBjeK38oe0oyfoSqMkd303Es3In8LObEIzKY5+JgdEi1AiABEDoc5DrykSRDp4lUzyD5wTPvsPMD6TMaVBonzBczhg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjzfTTACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoSnBAAgaydzYpqPMizgHq5UXBqDk4JQY3AEpOCEyRQuwSXaVVY61nV\r\nfyldJ7CBiy4aKhAnHIdONGTRtCl3saycFl8JOG9CDSRTMqUKek/3OraontHq\r\nYnMNM8qZiSotSdH4xZIj0sCulI26T1a3yfW/AbIRbKTDE5X8CAJhulRocfzA\r\noQUKmqlQcPvaAyHc656WewIg0qMlkW7XO56gs0tKZWOrNYwE8QVygc9SYkZ1\r\nc4iErxVfTkiz3hfp5dCTkkwLYLBSy0/adhoEB7jNfmj7gaH5SJs7ZzsvroaL\r\n45+1IGIodb17xznt32VQgh7X/r+EtBm6SCophvvJI0D6eD/Et/yAOlkMomv9\r\nrGBLepceFnKmc8768VsmMxg0DbWN88DtzDOQ/ghN7zK9rpOxaHSOG9EtPHEw\r\nUuGJJ3hN2JLazupxcKy6bSW8HerFNLD2STYM8+BWqFp/7L8/US+yQKXiM2+t\r\nKcs+070B1xFcOsJh4Lk6/nPuNZwBEGs6wPpAu3iqiDaEKvXF56qghRb8uK8R\r\nFD1dXG54j/E+PIpqkJrdxHY0QYn4gAslP2SKlBEPwnbrP2WnbaQv9MvhuWlu\r\nOc/VOpNxwU3CDYE2lPiByN6TGp7mEmKvMITPoksi5wftCvLZmYEaVOi9jmyR\r\nBsTXvqMiy/lBWyJvegbfKwJmLENQWu3xl8o=\r\n=Zy3D\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"4df57f174d5b407f8f3f2298bb0a2b6002e49daa","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^24.0.1","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1674441891652_1674441939616_0.45345479620375584","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1675044780414":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1675044780414","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1675044780414","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"3d57dc886905675b6e91d853128d2812e0cb575b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1675044780414.tgz","fileCount":8,"integrity":"sha512-bXy5P4yN3Z59492VB9MXJSRxZSkooD3gH5A+s9XWT2HuG8zTwCEy7zxhFCj9B+MokEOZgJR6JTvoTvIRgdrAcw==","signatures":[{"sig":"MEUCIQD997GDVIQFtzBykfYoXw1H61ml/NA7jOUmV+E4EX4S4AIgLHiSj2DIs9UmDjYtJzSa9oTcuIZMKEznxdJdk6VIvEI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj1yfcACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmosxhAAllqfsQWSFMp1/XrzGgt9uswt9luXmshhk9Ryk3LgrCRqzgmx\r\nHM7368PEaXpcjo8607TKmNQHKwPMpwk3DcRG8DRd+rwmY1E5qVWSGInsm0FU\r\ncwQoA/3P7jp8TNlCUL76evIxKInkrlJHuv8sb4ll4jPdV0tj6vi1cU97i10L\r\n5YIHToLcZitLRiOmD7q5HLnOtqOG204KJfye3gzAt19USfaHFn5JBx4BtPqe\r\nAay79mk+fJYKOS3DGKMjMLMwAu1aP7E0gsUPjZQ2XCU9k8LZs0AdfdkXm3cK\r\n6GcxzdIodSmUBhpThkxP5mUsm8TBUvBSG3F+/1vuiOaT7bk1j4g0LN3PDIFQ\r\nK8ocanuStVzQuS9tmMb5J644lSYGIB9MISovp2g5sX8wWun8+0xcTFYr7BSA\r\nZK2EogAyoBOejhB/yhBfj1XaGHjhdoudb3J3UzUU3RnSF9tedWZI1rV9qNnY\r\n3ZYedwAASPuSxIlOabrzW/L6s/am4ednTs5p7gSpetdEpWcw/a7uviQPBXzo\r\nDvlgRV1Up8lLVXVwBjmpjerpHX6LcNVvklNSs57dnyZmueqeZz4jlzWBLIcC\r\nbKaybxc4GJ7rEV+4evkbgOizPuI4pKGujXVQ6zXq5ueSagGgbBFk1CkUlXU6\r\n2C/oV91AQulx0jK/0zilFm248E4MNCSpyx4=\r\n=qRr6\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"53af6c7ac5fb9f73ab8989d918217a2b3998a84b","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.33.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1675044780414_1675044828308_0.459760509274187","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1676258231170":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1676258231170","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1676258231170","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"98dcb549a56d07b3b2860026429b768f8efb67e0","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1676258231170.tgz","fileCount":8,"integrity":"sha512-ri5YeSBhr3In0A81QughjZBV0TI3JKmG5eGjyZ+pl2fOAqkZybzyF0EQv2XBEtcCXxpnGMM++I6HnOU0FPQ30w==","signatures":[{"sig":"MEUCIQCqM2U7aYKn52ttX/2LNMTolhE+jvOSDYvqckPIh8bneAIgOSaE5ZD5TazOIH9I4eRUVyp5tviNY4Lx9TOySH/vqUw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj6avoACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmouIQ/9HeFIgVLKX2FErQa6dmzJRqSf6wLve13G+FBG5fEonZvb7snI\r\nObUB3gd2MYE4J1qwxpLnpfVFZ6c8PeI22Mqo5RceqvpIkC4IAYymowV5b1Xk\r\n1Guw5wOIdnQDwTyrSMav+61C1Jp9CrLeqwOp+TCM3zCew+90WeQRvKROaQBN\r\n8ucZObaOGbI79AHw6GQAKI2YmC8z+eW7nL8k5qsDvJLUvSg45v3smLL41nAK\r\nFAhugh/Le+IK9/XtuRVllRPqJvdqPhenZXTj7a6nrEH9l6UnjDVnt96F2c3r\r\nntVvWq9Ez9hql3+/vaDEQht9w3+ZnMfIJrHOw8baegRWkGBPTdU3m2vQadTo\r\n69379vAU8j0bzyi4FZ6FDWhA3gPPrUSa3bCA3mFLkaTV5YkSshacXuBlHsi5\r\n8lSuoY3anDeqJx6jdlvgDDFE/3UjmERuxUXW8BkBIKhMVrxLGq5rlzm1ZWvP\r\n+QueJLZRhqYIjy2B8n3Y+WJtzd0ML2SnGB8U57FYdfa75yYz8p4xoDW59wRA\r\nXsAcgDr7fDTQgddHM10fuq1HESINHe6Su8V+Laih+THEaAjeJzUGfshTDQjF\r\nr1JhrpZJK2kayoUKFjFp62qdw2LldiNltdPapKXord3F5R/pAHaQx1N7PF0k\r\n0XaHqrqjWCl4CLOA++Wr3QpnbRI0aKjZEKQ=\r\n=d54J\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"2d038b5d49a7dc96ca88910cad6d9a3b4d895091","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.34.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1676258231170_1676258280406_0.806495679440411","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1676258327053":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1676258327053","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1676258327053","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"faf385e5fecb8138bea89972a5e42af92ac67d5e","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1676258327053.tgz","fileCount":8,"integrity":"sha512-1QSce/GaK3R8gYxHaoBdVUFirsreS5ykoC5W02LBP2UUtMuohRzqpDChTMZkUoz4tAcwjzAaxdHu6bRfGrYHvw==","signatures":[{"sig":"MEUCIQDKdgRJVwIbR68CuG2SIQJD/dc4viehQuFAESpsCXpubwIgdS8jBkLG8mESjePX+dbiz3uoJSVsr3Spxgg16FacNSk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59613,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj6axEACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoeOg//SkCfgxJKbaAtu3Oz1mXqgKMm4PAX7VBtiuukO/W3f1bMlnVd\r\nYVCNTV++y98LOSMXWMG5NjUcwfSCYrf8aPMJ6SvcP0s3OAGL6vLOwBWlVbTw\r\n2BOW+GiuAt6sRouyfQFIUTubD67Puq5Y3/oyi2bRJaw+OBNUC6ngYkSmY7XP\r\n7RUtknVjiSP4uuF+eIs/qF3u7wjUgx9OpwdPV20TjUKGIqUIQoGzCWriw1hY\r\n47444o0/FlDOja196kY89kwoXqg5KicfwlXSkwz0PddqEiN25dgvKZjlBBOa\r\nEWdjURMBXWPU/Rssnb+hLp1pAckKvgJpXNByhMnjL8EqmRnRxjIya2vsCGwE\r\nqtao4OBntLtQ1nuBnWXI+5cJnymMQiCY4BFdJTO1JgRuM9dx3Hifo0hjr7R2\r\nz5PM5sgnWOyOb6ZJWcAXTcVrN1ATPl7npi4UMr4Gq6DvUfTeIkxuiluLG8Ab\r\n5+8K+xbeXD4L3YHWgNrfJeYHGYD6q7mE+JDE/KwV/M0ou+PGEF+GDHIE6jTt\r\nWqJW/qMNQQOvCuWvPz1I/S5G7D96ZtmWWJ12gOox3gocLFPmNCS6bw6PWqw5\r\npjCSpxptgCs8HboZI33Re57euc1PPrlj93+t8rgeHRWIFzoVL2kR6N/gZIAR\r\nPfnh43+GoR5fkzr+a9SxQ/kxRXEzRskyMjo=\r\n=msRN\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8093b2c44d7fa388d9a0fb5486fe27f3c209999e","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.25","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1676258327053_1676258372182_0.95719580572734","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1677467426904":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1677467426904","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1677467426904","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"502dc2d05c27e9c0b8d654cef2bcbace96da786c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1677467426904.tgz","fileCount":8,"integrity":"sha512-w4Wn8A9e+TKhDHE9TIB5LH5WfXNNSCSVCLkf6OHd9Uw0/7EDgcY52nuvDYhDLnZvayY8khVje4m6B2LyjvVMvg==","signatures":[{"sig":"MEQCIEjUKcdg7C0bTfOcdaoGk3FVj5j8kK4aGJCCXDXizaklAiB6b3zwWdY6LGr8JnrLer+sMPm2elE9nljr1KF5wxYixA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj/B9WACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrIYw/+JGqqbHWsDUycVl4OZ56/UUynrrgF5uKrqwKQ16FqyqGU6Dpv\r\naCbpDkybrHMhqdG5Gu4cSR1Q8So10HXJ2Hi8cq1SGTpIW7XCLXS2T9Mzi8Md\r\nzTcGf2FM1PBjJm5c47u3ELCrXZDOhy86ymj04V4jqw7kUG6IT/N9NejAw/YR\r\nNukGNeMQ6M/BtNWCSGOZkWRhabbGfGZIMffGnaBZlF71YLL37RzKoeSKh7+N\r\n98jr1ycUqf3/LVQ0GPflrl6G6kUHmJ/FeLkeLGb9xFHSVzhFfug5W+cLg+0y\r\nkF2HeiNgnPS92Y8qOdv7Z5WkxGq3SL4dWFfy8FwkVGWSFc2QjLxmK73UKsfk\r\nQsnU1EXbEJjEpn5X+O06Fb9IXsFbAQ2yoS48owKHqGMOj3A46ukiOgEVOfXV\r\n2n1fLN1lyBczE2kkvwDUn94xu4Mz7uLvYoyqEKeP0thLdqXGoZLgBzoU9ZsZ\r\n1WF9Kega41sram1mHdINk3XGrBExEPF/KQ6VWRSBuumU2qVpYfH7ielh2UL8\r\nZcVS+3kZBHBc4OiyS03QO7X5Zc2ZA2UEGo9HmbmN5A+5jmeCUwbtCxkXf5/n\r\nc0KiaNZmoCgqtnnTGC5Z1Q24rg+KBLbQVgyFHMa6Amy2ztDh/C/RE3xvi90/\r\nkLKg2NFa4KhE3pLswEObgGcOf1iLhZT///E=\r\n=Jh8z\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"96c2ceb24deccb5a2b5272d0e69aece89338afb0","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^8.35.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1677467426904_1677467478346_0.19704245366167816","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1677467447747":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1677467447747","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1677467447747","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"b23b1cc36a0f65b34b8acf2698c3a0faecd6469b","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1677467447747.tgz","fileCount":8,"integrity":"sha512-KAOVQmnw0HT8OftpNHSkSAceOxRo9/4OwQdzGx+0MrbMZx22eRGSIH5f1P1G8R4kdc06AtIvo6wan8JUntTqtw==","signatures":[{"sig":"MEUCIQDFdWXlBPMfzJ7Rz2tyUJRkpWTHdVQqeYQ63J4nt7DnAQIgej0Ucg5nWXBu3BpPM42i5APRU1MEhtoeVtMXYHxzhHU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59613,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj/B9tACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr/zQ/9HOE1CiJOXBf09FObSK2TjjZt+Y8uZ8aKL3HlDRF/z+gukeeS\r\n1k0cuU3J//LQwzOW0z83xT9xUvMK6S+m0LwAs5REVoKR1/XUcO/J406aauIC\r\n1pRuBdYvSDSAXP3CKvfzQpnguFA6T52J829G0unlLJ89kPJRVKJ5mWvXTTln\r\nIYpalDEkWQ9c1xhrQnCTfBuBgn5H01kf9VoYV6XMlqP7DfYfJla9r3DCxK9L\r\nZoeQOwuqEeGSp8AvRSmsrv7bnRcWTpkSQHsPJThO0Xn9J8UbPVegbLBB/mZ/\r\nt8/+d39AAVs/5iafWjJXa7azEqy2nAQuFjMrREAPo6dqXWxk+BkuEUrgzzsK\r\ntZLfIr7nOyTpX8n0o9aTmGkKjtD+yST4KqwYrSd06cYc3wT6B08s3nYjjnCN\r\nWmgnu7ySvqlWbjMgHGuOvUDdSbsiLkpfWfFcQbeW4Y0P1w6+OCyLWaPrBKZ6\r\n3flrje2BxuWvXcvrCBn817FJBu/K95OeplEa+VntutXzkYZEf+IJFRle5DJQ\r\nQ9tIVDIqD1gnYt8K+cpf4VRa6Fdro4hknobUuvwJOa0AW4HdJAJFzZDU2qsY\r\nx17mLUwP3dLUYuud+suNzQr6uFhZTeZ0jmBkOKO+CBfKflrlZ73To92j8jBJ\r\nfAQuAb1WNosyJSKOo1u8FvMOAZDEKfIc9Ks=\r\n=hCXq\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"8050459e5d118a593249469f93528e009462fcbf","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.23.26","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1677467447747_1677467501402_0.13992038625565306","host":"s3://npm-registry-packages"}},"1.0.1-canary-f07d762-1677979873279":{"name":"@iadvize-oss/opaque-union","version":"1.0.1-canary-f07d762-1677979873279","keywords":["iAdvize"],"author":{"name":"iAdvize developers"},"license":"MIT","_id":"@iadvize-oss/opaque-union@1.0.1-canary-f07d762-1677979873279","maintainers":[{"name":"etiennerd","email":"rouillard.etienne@gmail.com"},{"name":"jules.trehorel","email":"jules.trehorel@iadvize.com"},{"name":"cffparisot","email":"cecile.parisot@iadvize.com"},{"name":"davidiadvize","email":"david.bonnemaison@iadvize.com"},{"name":"ltaloc","email":"loic.taloc@iadvize.com"},{"name":"mguihal.iadvize","email":"maxime.guihal@iadvize.com"},{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},{"name":"euphocat","email":"nicolas.baptiste@gmail.com"}],"homepage":"https://github.com/iadvize/opaque-union-library#readme","bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"dist":{"shasum":"3c8e8dcae1aa7a97c4c998a7884dc1a8d0595f9c","tarball":"https://registry.npmjs.org/@iadvize-oss/opaque-union/-/opaque-union-1.0.1-canary-f07d762-1677979873279.tgz","fileCount":8,"integrity":"sha512-Acs6AoLbC8/58Qh90h6TQcJnlomLUpaz4x9W4wlcWeD9pwDFRgV+d/A080vYQ9ZzRrJmrUOvNZi9lA6+5EV6AQ==","signatures":[{"sig":"MEQCICd5ePxxrUxYPUkPXH0Em+1iuQkVZez4NBrxURXfrEjuAiBIYRiqCxr8Sy+SS1tfUcbr3iWw/XTClAcQ9TT5vCxUWg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkA/EUACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoCfw//QuJ+W4Rcs/pj4I0HvyXjTXnHsuddOpnRgAoysOiS1IWL1zYq\r\nh0EXISTXhEJKNddQhinHja0i2LkDp6/L3cVLRiINzTUk+Ex2xb+LygfZf8Mt\r\nqNz6NS5NGTSG2FjeqRxW1i4lvOkAIM9gRwiVa7dW5nLHrLANtO2UgVNI2Xuu\r\nYaYm8eFLIaSaUFNB5ZsR4HxrCqvbEGzYE1onPpDhLbI/iyV2aOBGjaNrHl0u\r\n/VyFQbUL0Lqr6D55yDQHDVV1rP5zGGTy7rNSYBZza47E18nmC0DTJAAGio5p\r\nM3ubwF+cUg4LruEtaYjAQJ1f2aNjGumK0p4DrazRRJFI/0ivwHMQ7igVzKpQ\r\n4bpJW5DNuLKoiHi64FfVWzsRGnGYdiUutR0HCoc9+0eWM9Tm29pvRqbCM//M\r\nP1RQRMMfuzK6U3mwIcHxNkte7FaGYsCdmINjLruKnXt3BLQkecwfnBIrUKtI\r\n+BqNo1EbaiL4UxUtNqgef14jTCkw4JH/yFqFUP8ewvWM1bVtnpoNc0nDwDx+\r\nkHSAtpOHIfobRa9ysIndhKqEbujae/lsNoCtAxOw/+qPPDSsDnjw7JWp3CNN\r\n5AiCzyOONQM9O/U6mvg656D7eNd/L9ArX6aSmaDMspy45K354Wz2zQxAiO9s\r\nvfRtwi6rNq2Ceg/2w4qe0AyL+qOsRX6hKcQ=\r\n=1D75\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","types":"dist/index.d.ts","module":"esm/index.js","readme":"@iadvize-oss/opaque-union library\n=============================\n![Continuous integration](https://github.com/iadvize/opaque-union-library/workflows/Continuous%20integration/badge.svg)\n\nThis experimental library provides helpers to create and maintain opaque domain\nsumtypes in Typescript.\n\nInspired by https://github.com/sledorze/morphic-ts/ and\nhttps://github.com/iadvize/opaque-type-library/.\n\n# Example\n\nLet's say your app deals with messages: \n\n```typescript\n// message.ts\n\ntype $Text = {\n  author: string;\n  content: string;\n}\n\ntype $Image = {\n  author: string;\n  source: string;\n  description: string;\n  mimetype: 'jpeg' | 'png',\n}\n\ntype $Video = {\n  author: string;\n  source: string;\n  description: string;\n  autoplay: boolean;\n}\n\ntype $Message = $Text | $Image | $Video;\n```\n\nThese are your private types (we like to prefix them with `$`). You don't want\nto expose them directly. You want to make them *opaque* for the rest of your app\nand expose an API to use them.\n\nLet's create the opaque union helper:\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.of({\n  Text: Union.type<$Text>(),\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport type Text = ReturnType<typeof MessageAPI.of.Text>; // Union.Opaque<'Text'>\nexport type Image = ReturnType<typeof MessageAPI.of.Image>;\nexport type Video = ReturnType<typeof MessageAPI.of.Video>;\n\n// this is a union of each opaque type\n// ie. Text | Image | Video\nexport type Message = Union.Type<typeof MessageAPI>;\n```\n\nAn helper for media messages only will also be helpful.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MediaMessageAPI = Union.omit(MessageAPI, ['Text']);\n```\n\nYou can now easily create the API you want your module to expose.\n\nFirst, constructors:\n\n```typescript\n// message.ts\n\nexport const createText = MessageAPI.of.Text; // (props: $Text) => Union.Opaque<'Text'>\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\n```\n\nTo be used somewhere else in your app like that:\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textMessage = Message.createText({ // textMessage is opaque\n  author: 'Jean',\n  content: 'Hello world!',\n});\n\nconst imageMessage = Message.createImage({\n  author: 'Peter',\n  source: 'http://...',\n  description: 'A goat',\n  mimetype: 'jpeg',\n});\n```\n\nWe can't work directly on the opaque `textMessage` or `imageMessage` variables\nbecause we can't see what's inside.\n\n```typescript\n// Error: Property 'author' does not exist on type 'Opaque<\"Text\">'.\ntextMessage.author\n```\n\nYou're safe. Only `MessageAPI` knows how to \"unopaque\" these variables and work\non their content. It's best to keep the API private to your `message.ts` module.\n\nTo help you do just that, you can write properties accessors easily:\n\n```typescript\n// message.ts\n\nexport const author = MessageAPI.lensFromProp('author').get;\n\nexport const content = MessageAPI.Text.lensFromProp('content').get;\n\nexport const source = MediaMessageAPI.lensFromProp('source').get;\n\nexport const description = MediaMessageAPI.lensFromProp('description').get;\n\nexport const mimetype = MessageAPI.Image.lensFromProp('mimetype').get;\n\nexport const autoplay = MessageAPI.Video.lensFromProp('autoplay').get;\n```\n\nTo be used in another file like this: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nconst textContent = Message.content(textMessage);\nconst imageDescription = Message.description(imageMessage);\n```\n\nYou can create more powerful and time saving compound accessors as well:\n\n```typescript\n// message.ts\n\nexport const summary = MessageAPI.fold({\n  Text: text => `${author(text)} send \"${content(text)}\"`,\n  Image: image => `${author(image)} send a ${mimetype(image)} image \"${description(image)}\"`,\n  Video: video => `${author(video)} send a video \"${description(video)}\"`,\n});\n```\n\nTo be used for example like that: \n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nfunction log(message: Message.Message) {\n  console.log(Message.summary(message));\n}\n```\n\nYou can write transformations:\n\n```typescript\n// message.ts\n\nexport const addSignature = (signature: string) => MessageAPI.Text.iso.modify(\n  $text => ({ ...$text, content: `${$text.content}\\n${signature}` })\n);\n```\n\nIt's very composable. For example here with\n[fp-ts](https://gcanti.github.io/fp-ts/modules/) `pipe` function:\n\n```typescript\nimport { pipe } from 'fp-ts/es6/function';\nimport * as Message from './path/to/message.ts';\n\nconst signature = 'Jean (jean@email.com)';\n\nconst textMessageWithSignature = pipe(\n  Message.createText(...),\n  Message.addSignature(signature),\n);\n```\n\nAnd finally, the classic helpers you've come to expect come bundled in:\n\n```typescript\n// message.ts\n\nexport const isText = MessageAPI.is.Text;\nexport const fold = MessageAPI.fold;\n```\n\n```typescript\nimport * as Message from './path/to/message.ts';\n\nif (Message.isText(message)) {\n  return <TextMessage message={message}>\n} else {\n  return <UnsupportedMessage >\n}\n\n// or\n\nreturn pipe(\n  message,\n  Message.fold({\n    Text: text => <TextMessage message={text} />,\n    Image: () => <UnsupportedMessage />,\n    Video: () => <UnsupportedMessage />,\n  }),\n);\n```\n\n# Advanced example\n\nWhat if a Message should be either `Pending` or `Sent`? This is what is called\n\"variation\" in the library.\n\n```typescript\n// message.ts\n\nimport * as Union from '@iadvize-oss/opaque-union';\n\nconst MessageAPI = Union.ofVariations({\n  Text: {\n    Pending: Union.type<$Text>(),\n    Sent: Union.type<$Text>(),\n  },\n  Image: {\n    Pending: Union.type<$Image>(),\n    Sent: Union.type<$Image>(),\n  },\n});\n\nconst pendingTextMessage = MessageAPI.of.Text.Pending({ ... });\n```\n\nUsing variations, you will be able to model your entities with a table, like\nbelow, while still using all the library union helpers.\n\n|         | Text | Image |\n|---------|------|-------|\n| Pending |      |       |\n| Sent    |      |       |\n\n\n# Install\n\n```\nnpm add @iadvize-oss/opaque-union\n```\n\n# Documentation\n\n[📖 Documentation](https://iadvize.github.io/opaque-union-library/)\n\n# Optics\n\nThe union API exposes some [monocle-ts](https://github.com/gcanti/monocle-ts)\noptics:\n\n## `Iso`\n\nAn `Iso` is a tool to transform between two types without any loss. In our case:\n\n```\n  Opaque<Key> ---> Type (get, from, unwrap)\n  Opaque<Key> <--- Type (reverseGet, to, wrap)\n```\n\nIt's particulary useful to transform the private value inside the opaque but you\ncan also combine it with other\n[monocle-ts](https://github.com/gcanti/monocle-ts) optics. \n\nUse `<API>.<Type>.iso` to have full control over one type and its corresponding\nopaque type.\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst fromOpaque: (text: Text) => $Text = iso.from;\nconst toOpaque: ($text: $Text) => Text = iso.to;\n```\n\nTo be used like this, when you need to \"unopaque\" your type in a private module\nfunction, for example:\n\n```typescript\nfunction translate(textMessage: Text): Text { \n  const privateContent = fromOpaque(\n    textMessage, // this is an Opaque<'Text'>\n  ); // \"hello world\"\n    \n  const translation = translateText(privateContent); // some magic here\n\n  const opaqueTextMessageAgain = toOpaque(\n    translation, // this is a $Text\n  ); // Opaque<'Text'>\n\n  return opaqueTextMessageAgain\n}\n```\n\nYou can also use the `Iso` directly for transformations:\n\n```typescript\nconst iso = MessageAPI.Text.iso; // Iso<Opaque<Type>, Type>\n\nconst addSignature = (signature: string) => iso.modify(\n  // you have access to the private type here\n  $text => `${$text}\\n${signature}`,\n);\n```\n\nTo be used like this:\n\n```typescript\nconst textMessage: Text = ...;\n\nconst textMessageWithSignature = addSignature('Jean (jean@email.com)')(textMessage);\n```\n\nThere is also a global `Iso` exposed on `<API>.iso` to switch between any opaque\nand any private types. \n\n```typescript\nconst iso: Iso<\n  Message, // the opaque union\n  Union.Tagged<$Computer, 'Computer'> | Union.Tagged<$Smartphone, 'Smartphone'> | Union.Tagged<$Smartphone, 'Smartphone'>\n> = MessageAPI.iso;\n```\n\nWhere `type Tagged<T, Name> = T & { _key: Name }` is used to not lose the type\nof the entity when switching from an opaque to the corresponding private type.\nThat's why the global `.iso` is restricted to members of the union that are\nassignabled to `object`.\n\n## `lensFromProp`\n\nA [monocle-ts](https://github.com/gcanti/monocle-ts) `Lens` is a tool to\ntransform between a type and a subtype of it.\n\nUse the global `<API>.lensFromProp` to create a `Lens` between any opaque of the\nAPI and a property shared by all private types of the API (if any).\n\nIn your module:\n\n```typescript\n// media.ts\ntype $Image = {\n  source: string;\n}\n\ntype $Video = {\n  source: string;\n  autoplay: boolean;\n}\n\nconst MediaAPI = Union.of({\n  Image: Union.type<$Image>(),\n  Video: Union.type<$Video>(),\n});\n\nexport const createImage = MessageAPI.of.Image;\nexport const createVideo = MessageAPI.of.Video;\n\nexport const source = MediaAPI.lensFromProp('source').get;\nexport const updateSource = MediaAPI.lensFromProp('source').modify;\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst image = Media.createImage({ source: 'http://a.com/b.jpeg ' });\n\nconsole.log('source: ', source(image)); // http://a.com/b.jpeg\n\nconst newImage = Media.updateSource(\n  oldSource => oldSource.replace('a.com', 'static.a.com')\n)(image);\n```\n\nUse `<API>.<Type>.lensFromProp` to create an `Lens<Opaque<Type>, Type[...]`.\n\n```typescript\nconst videoMessage: Video = ...;\n\nconst autoplay = MediaAPI.Video.lensFromProp('autoplay').get;\nconst removeAutoPlay = MediaAPI.Video.lensFromProp('autoplay').set(false);\n```\n\nSomewhere else in your app:\n\n```typescript\nimport * as Media from './path/to/media.ts';\n\nconst video = Media.createImage({ source: 'http://a.com/b.jpeg ', autoplay: true });\n\nconst videoWithoutAutoplay = Media.removeAutoPlay(video);\n```\n","gitHead":"891653bd08077c91b15d7d1b2ab1ebe96169f638","private":false,"scripts":{"docs":"typedoc","build":"rm -rf dist esm && rollup -c","lint:js":"eslint . --ext .js,.jsx,.ts,.tsx,.json,.d.ts --cache","test:js":"jest --coverage"},"_npmUser":{"name":"iadvize-bot","email":"npm-iadvize-oss@iadvize.com"},"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"_npmVersion":"6.14.12","description":"Functional opaque union api for Typescript and Javascript","directories":{},"sideEffects":false,"_nodeVersion":"10.24.1","dependencies":{"monocle-ts":"^2.3.3","@iadvize-oss/foldable-helpers":"^2.2.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsd":"^0.17.0","jest":"^26.6.3","tslib":"^2.0.3","eslint":"^7.14.0","rollup":"^2.33.3","ts-jest":"^26.4.4","typedoc":"^0.21.0","typescript":"^4.1.2","@types/jest":"^26.0.15","rollup-plugin-terser":"^7.0.2","@rollup/plugin-commonjs":"^19.0.0","rollup-plugin-multi-input":"^1.1.1","rollup-plugin-typescript2":"^0.30.0","@iadvize-oss/eslint-config":"^2.2.0","@iadvize-oss/eslint-config-jest":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/opaque-union_1.0.1-canary-f07d762-1677979873279_1677979924495_0.30225427699888474","host":"s3://npm-registry-packages"}}},"time":{"created":"2020-06-21T09:14:14.873Z","modified":"2025-10-22T09:22:09.999Z","0.0.0-canary-503ebf9-1592730802608":"2020-06-21T09:14:15.250Z","0.0.1-beta.0":"2020-06-21T09:21:04.561Z","0.0.1-beta.0-canary-41ad66e-1592731368163":"2020-06-21T09:23:53.410Z","0.0.1-beta.0-canary-995808e-1593027755533":"2020-06-24T19:43:30.937Z","0.0.1-beta.0-canary-831d4d8-1593027800892":"2020-06-24T19:44:11.229Z","0.0.1-beta.0-canary-e841429-1593027895970":"2020-06-24T19:45:42.286Z","0.0.1-beta.0-canary-ee026d8-1593028051773":"2020-06-24T19:48:20.106Z","0.0.1-beta.0-canary-4cc19c6-1593070748555":"2020-06-25T07:39:58.669Z","0.0.1-beta.0-canary-24fd182-1593071590447":"2020-06-25T07:54:11.511Z","0.0.1-beta.0-canary-174f279-1593071762363":"2020-06-25T07:56:58.976Z","0.0.1-beta.0-canary-a42cfe7-1593631888948":"2020-07-01T19:32:13.981Z","0.0.1-beta.0-canary-7190ff7-1593632790090":"2020-07-01T19:47:18.132Z","0.0.1-beta.0-canary-699ea67-1593685939770":"2020-07-02T10:33:25.770Z","0.0.1-beta.0-canary-5c9327f-1594021143089":"2020-07-06T07:39:47.611Z","0.0.1-beta.0-canary-421966e-1594025972328":"2020-07-06T09:00:41.678Z","0.0.1-beta.0-canary-d28001e-1594029060654":"2020-07-06T09:52:00.511Z","0.0.1-beta.0-canary-e0d08dd-1594029765669":"2020-07-06T10:03:52.134Z","0.0.1-beta.0-canary-3dc161c-1594033988458":"2020-07-06T11:13:56.634Z","0.0.1-beta.0-canary-f1bc93a-1594062142098":"2020-07-06T19:03:15.472Z","0.0.1-beta.0-canary-6350a5c-1594114758951":"2020-07-07T09:40:23.093Z","0.0.1-beta.0-canary-3d46d79-1594115666859":"2020-07-07T09:55:19.416Z","0.0.1-beta.0-canary-88da17d-1594115772168":"2020-07-07T09:57:00.769Z","0.0.1-beta.0-canary-875ec7e-1594121737141":"2020-07-07T11:36:44.884Z","0.0.1-beta.0-canary-f4b6fca-1594122413614":"2020-07-07T11:47:49.534Z","0.0.1-beta.0-canary-4546cf9-1594145193712":"2020-07-07T18:07:28.184Z","0.0.1-beta.0-canary-b2db077-1594146547980":"2020-07-07T18:30:01.852Z","0.0.1-beta.0-canary-da75b0f-1594148105144":"2020-07-07T18:55:58.383Z","0.0.1-beta.0-canary-90be954-1594154163818":"2020-07-07T20:36:50.359Z","0.0.1-beta.0-canary-6883f82-1594278097863":"2020-07-09T07:02:42.522Z","0.0.1-beta.0-canary-e644d81-1594284853228":"2020-07-09T08:55:08.188Z","0.0.1-beta.0-canary-ffd9f0d-1594818890654":"2020-07-15T13:16:02.711Z","0.0.1-beta.0-canary-afa3c0e-1594821096026":"2020-07-15T13:52:29.084Z","0.0.1-beta.0-canary-e4626ea-1595309115749":"2020-07-21T05:26:14.640Z","0.0.1-beta.0-canary-2a89d67-1595401567705":"2020-07-22T07:07:04.941Z","0.0.1-beta.0-canary-61380a0-1595776003510":"2020-07-26T15:07:30.299Z","0.0.1-beta.0-canary-9deb3d7-1595778576110":"2020-07-26T15:50:29.585Z","0.0.1-beta.0-canary-ba286b3-1595778842932":"2020-07-26T15:54:57.934Z","0.0.1-beta.0-canary-7aee527-1595779506745":"2020-07-26T16:05:56.388Z","0.0.1-beta.0-canary-7ebb861-1595779992746":"2020-07-26T16:14:11.219Z","0.0.1-beta.0-canary-a1b16a6-1597312139040":"2020-08-13T09:49:45.060Z","0.0.1-beta.0-canary-555c0d1-1597312766029":"2020-08-13T10:00:17.816Z","0.0.1-beta.0-canary-20912ef-1597312991148":"2020-08-13T10:04:11.670Z","0.0.1-beta.0-canary-a54dd17-1597313977707":"2020-08-13T10:20:25.879Z","0.0.1-beta.0-canary-e5e6a73-1606260801933":"2020-11-24T23:34:14.750Z","0.0.1-beta.0-canary-8570e70-1606292401028":"2020-11-25T08:20:51.722Z","0.0.1-beta.0-canary-9f761ed-1606485464437":"2020-11-27T13:58:37.356Z","0.0.1-beta.0-canary-12e7c42-1606486142836":"2020-11-27T14:09:52.581Z","0.0.1-beta.0-canary-a4577e4-1606486368796":"2020-11-27T14:13:47.254Z","0.0.1-beta.0-canary-d41fe89-1606495585351":"2020-11-27T16:47:14.188Z","0.0.1-beta.0-canary-92be957-1606731001013":"2020-11-30T10:11:14.282Z","0.0.1-beta.0-canary-9cd51e3-1606731377063":"2020-11-30T10:17:13.072Z","0.0.1-beta.1":"2020-11-30T10:26:46.777Z","0.0.1-beta.1-canary-2783bc8-1606732279589":"2020-11-30T10:32:16.183Z","1.0.0":"2020-11-30T10:40:09.472Z","1.0.0-canary-1c65345-1607115545094":"2020-12-04T20:59:55.927Z","1.0.0-canary-fa8d5e2-1607812234888":"2020-12-12T22:31:30.466Z","1.0.0-canary-07fca8a-1608660098520":"2020-12-22T18:02:25.581Z","1.0.0-canary-25d80d2-1617264623120":"2021-04-01T08:11:27.019Z","1.0.0-canary-b9a82a0-1619732791781":"2021-04-29T21:47:21.062Z","1.0.0-canary-cfb0616-1622558091338":"2021-06-01T14:35:46.221Z","1.0.0-canary-cfb0616-1622558101081":"2021-06-01T14:35:55.977Z","1.0.0-canary-22d3af7-1622558336716":"2021-06-01T14:39:53.946Z","1.0.0-canary-22d3af7-1622558474645":"2021-06-01T14:41:58.206Z","1.0.0-canary-04903b0-1622558756695":"2021-06-01T14:47:13.505Z","1.0.0-canary-2c5d75e-1622559635057":"2021-06-01T15:01:39.702Z","1.0.0-canary-2741463-1622560304938":"2021-06-01T15:12:30.776Z","1.0.0-canary-de4c831-1622560624810":"2021-06-01T15:17:49.985Z","1.0.1":"2021-06-01T15:51:56.871Z","1.0.1-canary-e828954-1622599379480":"2021-06-02T02:03:52.915Z","1.0.1-canary-e828954-1622599401422":"2021-06-02T02:04:22.666Z","1.0.1-canary-e828954-1622599428397":"2021-06-02T02:04:48.094Z","1.0.1-canary-e828954-1622599460736":"2021-06-02T02:05:12.466Z","1.0.1-canary-82aa02d-1622622027987":"2021-06-02T08:21:14.642Z","1.0.1-canary-a13c986-1622626694650":"2021-06-02T09:45:25.055Z","1.0.1-canary-a13c986-1622626732673":"2021-06-02T09:45:54.660Z","1.0.1-canary-c299010-1622685700266":"2021-06-03T02:02:31.208Z","1.0.1-canary-c299010-1622685695358":"2021-06-03T02:02:48.135Z","1.0.1-canary-c299010-1622685721681":"2021-06-03T02:03:06.925Z","1.0.1-canary-c299010-1622685736571":"2021-06-03T02:03:13.091Z","1.0.1-canary-c299010-1622685713560":"2021-06-03T02:03:39.044Z","1.0.1-canary-c89b970-1622710257757":"2021-06-03T08:51:57.901Z","1.0.1-canary-c89b970-1622710260498":"2021-06-03T09:02:14.958Z","1.0.1-canary-492609d-1622711125483":"2021-06-03T09:06:25.376Z","1.0.1-canary-492609d-1622711126166":"2021-06-03T09:06:30.057Z","1.0.1-canary-492609d-1622711128865":"2021-06-03T09:06:35.809Z","1.0.1-canary-37f0dc6-1622772106711":"2021-06-04T02:02:49.001Z","1.0.1-canary-37f0dc6-1622772118990":"2021-06-04T02:03:05.387Z","1.0.1-canary-37f0dc6-1622772136217":"2021-06-04T02:03:13.665Z","1.0.1-canary-37f0dc6-1622772157545":"2021-06-04T02:03:45.626Z","1.0.1-canary-799abd2-1623031301194":"2021-06-07T02:02:29.853Z","1.0.1-canary-799abd2-1623031322256":"2021-06-07T02:03:00.936Z","1.0.1-canary-799abd2-1623031341155":"2021-06-07T02:03:23.666Z","1.0.1-canary-6890547-1623055506199":"2021-06-07T08:45:56.595Z","1.0.1-canary-6890547-1623204100365":"2021-06-09T02:02:38.255Z","1.0.1-canary-bb18c0b-1623636094178":"2021-06-14T02:02:30.984Z","1.0.1-canary-bb18c0b-1623636116080":"2021-06-14T02:02:53.914Z","1.0.1-canary-a96e62a-1623895320134":"2021-06-17T02:02:54.253Z","1.0.1-canary-a96e62a-1623895331260":"2021-06-17T02:03:03.590Z","1.0.1-canary-a96e62a-1623895353105":"2021-06-17T02:03:30.299Z","1.0.1-canary-4b6b557-1623981696441":"2021-06-18T02:02:26.647Z","1.0.1-canary-4b6b557-1623981706276":"2021-06-18T02:02:50.137Z","1.0.1-canary-4660650-1624240879986":"2021-06-21T02:02:10.716Z","1.0.1-canary-4660650-1624240894473":"2021-06-21T02:02:24.579Z","1.0.1-canary-c2c1dd0-1624327276179":"2021-06-22T02:02:01.424Z","1.0.1-canary-6148f5e-1624413704884":"2021-06-23T02:02:32.376Z","1.0.1-canary-6148f5e-1624845686121":"2021-06-28T02:02:19.644Z","1.0.1-canary-6148f5e-1624845697597":"2021-06-28T02:02:28.432Z","1.0.1-canary-3c24b8c-1624932095173":"2021-06-29T02:02:19.472Z","1.0.1-canary-3c24b8c-1625104915737":"2021-07-01T02:02:45.716Z","1.0.1-canary-3c24b8c-1625104931950":"2021-07-01T02:03:10.452Z","1.0.1-canary-8ac59cc-1625191292560":"2021-07-02T02:02:19.558Z","1.0.1-canary-3a35ae8-1625450487402":"2021-07-05T02:02:22.734Z","1.0.1-canary-316b40c-1625623277944":"2021-07-07T02:02:10.191Z","1.0.1-canary-9a5082e-1625642848254":"2021-07-07T07:28:17.822Z","1.0.1-canary-9a5082e-1625709708360":"2021-07-08T02:02:36.563Z","1.0.1-canary-1a2439b-1626055312419":"2021-07-12T02:02:40.591Z","1.0.1-canary-d8a03f2-1626400898820":"2021-07-16T02:02:29.456Z","1.0.1-canary-d8a03f2-1626400909081":"2021-07-16T02:02:41.760Z","1.0.1-canary-2fb4fd2-1626660476713":"2021-07-19T02:08:46.350Z","1.0.1-canary-d3ea5cf-1626919299486":"2021-07-22T02:02:28.647Z","1.0.1-canary-a8c0b11-1627264897950":"2021-07-26T02:02:33.935Z","1.0.1-canary-1ea1131-1627351299847":"2021-07-27T02:02:44.796Z","1.0.1-canary-6e7a4cb-1627524096338":"2021-07-29T02:02:31.787Z","1.0.1-canary-2c88a36-1627610493388":"2021-07-30T02:02:17.429Z","1.0.1-canary-f07d762-1627869696548":"2021-08-02T02:02:32.034Z","1.0.1-canary-f07d762-1627869711930":"2021-08-02T02:02:41.460Z","1.0.1-canary-f07d762-1627869720614":"2021-08-02T02:02:54.421Z","1.0.1-canary-f07d762-1628215314944":"2021-08-06T02:02:42.524Z","1.0.1-canary-f07d762-1628474496337":"2021-08-09T02:02:27.207Z","1.0.1-canary-f07d762-1628647347029":"2021-08-11T02:03:28.080Z","1.0.1-canary-f07d762-1628647387318":"2021-08-11T02:03:56.468Z","1.0.1-canary-f07d762-1628820112878":"2021-08-13T02:02:40.646Z","1.0.1-canary-f07d762-1629424898426":"2021-08-20T02:02:47.593Z","1.0.1-canary-f07d762-1629770518609":"2021-08-24T02:02:52.749Z","1.0.1-canary-f07d762-1630288984407":"2021-08-30T02:04:00.630Z","1.0.1-canary-f07d762-1631498614639":"2021-09-13T02:04:36.478Z","1.0.1-canary-f07d762-1632103286904":"2021-09-20T02:02:51.525Z","1.0.1-canary-f07d762-1632276096910":"2021-09-22T02:02:38.351Z","1.0.1-canary-f07d762-1632362499686":"2021-09-23T02:02:29.391Z","1.0.1-canary-f07d762-1633313001120":"2021-10-04T02:04:16.248Z","1.0.1-canary-f07d762-1633313028711":"2021-10-04T02:04:42.043Z","1.0.1-canary-f07d762-1633313119645":"2021-10-04T02:06:17.057Z","1.0.1-canary-f07d762-1633917878497":"2021-10-11T02:05:32.713Z","1.0.1-canary-f07d762-1634263346049":"2021-10-15T02:03:43.255Z","1.0.1-canary-f07d762-1634522556199":"2021-10-18T02:03:39.396Z","1.0.1-canary-f07d762-1634695308650":"2021-10-20T02:02:48.384Z","1.0.1-canary-f07d762-1635127386846":"2021-10-25T02:04:08.068Z","1.0.1-canary-f07d762-1635127408266":"2021-10-25T02:04:25.801Z","1.0.1-canary-f07d762-1635213770198":"2021-10-26T02:03:50.790Z","1.0.1-canary-f07d762-1635818504628":"2021-11-02T02:02:39.225Z","1.0.1-canary-f07d762-1636337068092":"2021-11-08T02:05:22.449Z","1.0.1-canary-f07d762-1636337092870":"2021-11-08T02:05:50.449Z","1.0.1-canary-f07d762-1636941720315":"2021-11-15T02:02:59.320Z","1.0.1-canary-f07d762-1636941823473":"2021-11-15T02:04:40.016Z","1.0.1-canary-f07d762-1637287404307":"2021-11-19T02:04:21.355Z","1.0.1-canary-f07d762-1637546660946":"2021-11-22T02:05:17.834Z","1.0.1-canary-f07d762-1637632921253":"2021-11-23T02:02:59.447Z","1.0.1-canary-f07d762-1637805733845":"2021-11-25T02:03:03.731Z","1.0.1-canary-f07d762-1638324127149":"2021-12-01T02:02:51.820Z","1.0.1-canary-f07d762-1638756223599":"2021-12-06T02:04:39.434Z","1.0.1-canary-f07d762-1638842580192":"2021-12-07T02:03:46.807Z","1.0.1-canary-f07d762-1639101765011":"2021-12-10T02:03:32.670Z","1.0.1-canary-f07d762-1639361013854":"2021-12-13T02:04:25.330Z","1.0.1-canary-f07d762-1639965834905":"2021-12-20T02:04:45.606Z","1.0.1-canary-f07d762-1640570599778":"2021-12-27T02:06:05.031Z","1.0.1-canary-f07d762-1640916188050":"2021-12-31T02:04:03.418Z","1.0.1-canary-f07d762-1641175490579":"2022-01-03T02:05:42.088Z","1.0.1-canary-f07d762-1641348124460":"2022-01-05T02:02:54.576Z","1.0.1-canary-f07d762-1642385059185":"2022-01-17T02:05:03.079Z","1.0.1-canary-f07d762-1642385085432":"2022-01-17T02:05:33.764Z","1.0.1-canary-f07d762-1642557710679":"2022-01-19T02:02:35.780Z","1.0.1-canary-f07d762-1642989708617":"2022-01-24T02:02:33.984Z","1.0.1-canary-f07d762-1643162527885":"2022-01-26T02:02:52.670Z","1.0.1-canary-f07d762-1643594633123":"2022-01-31T02:04:43.268Z","1.0.1-canary-f07d762-1643853809186":"2022-02-03T02:04:14.354Z","1.0.1-canary-f07d762-1644285846227":"2022-02-08T02:04:52.396Z","1.0.1-canary-f07d762-1644545319066":"2022-02-11T02:09:27.008Z","1.0.1-canary-f07d762-1644804191958":"2022-02-14T02:04:00.795Z","1.0.1-canary-f07d762-1645408911424":"2022-02-21T02:02:47.463Z","1.0.1-canary-f07d762-1645409051123":"2022-02-21T02:05:15.934Z","1.0.1-canary-f07d762-1645581802668":"2022-02-23T02:04:12.451Z","1.0.1-canary-f07d762-1645668201733":"2022-02-24T02:04:14.257Z","1.0.1-canary-f07d762-1645668210427":"2022-02-24T02:04:22.282Z","1.0.1-canary-f07d762-1646013853556":"2022-02-28T02:05:12.943Z","1.0.1-canary-f07d762-1646272950919":"2022-03-03T02:03:28.647Z","1.0.1-canary-f07d762-1646618581203":"2022-03-07T02:03:49.614Z","1.0.1-canary-f07d762-1646618591074":"2022-03-07T02:03:59.928Z","1.0.1-canary-f07d762-1646704957908":"2022-03-08T02:03:23.303Z","1.0.1-canary-f07d762-1647223402354":"2022-03-14T02:04:09.257Z","1.0.1-canary-f07d762-1647309860824":"2022-03-15T02:05:10.252Z","1.0.1-canary-f07d762-1648335406187":"2022-03-26T22:57:27.654Z","1.0.1-canary-f07d762-1648432949467":"2022-03-28T02:03:23.929Z","1.0.1-canary-f07d762-1648433038403":"2022-03-28T02:04:43.303Z","1.0.1-canary-f07d762-1649383413667":"2022-04-08T02:04:26.317Z","1.0.1-canary-f07d762-1649642533205":"2022-04-11T02:03:04.325Z","1.0.1-canary-f07d762-1649642643089":"2022-04-11T02:04:56.336Z","1.0.1-canary-f07d762-1650247441447":"2022-04-18T02:04:48.181Z","1.0.1-canary-f07d762-1650247487211":"2022-04-18T02:05:35.406Z","1.0.1-canary-f07d762-1650855285310":"2022-04-25T02:55:44.960Z","1.0.1-canary-f07d762-1651457039507":"2022-05-02T02:04:50.814Z","1.0.1-canary-f07d762-1651543362807":"2022-05-03T02:03:31.111Z","1.0.1-canary-f07d762-1651802517935":"2022-05-06T02:02:48.153Z","1.0.1-canary-f07d762-1652063188729":"2022-05-09T02:27:14.279Z","1.0.1-canary-f07d762-1652063174415":"2022-05-09T02:31:45.408Z","1.0.1-canary-f07d762-1652666579732":"2022-05-16T02:04:24.209Z","1.0.1-canary-f07d762-1653012197332":"2022-05-20T02:04:09.642Z","1.0.1-canary-f07d762-1653271344220":"2022-05-23T02:03:19.428Z","1.0.1-canary-f07d762-1653876120437":"2022-05-30T02:02:46.813Z","1.0.1-canary-f07d762-1653962587438":"2022-05-31T02:04:03.048Z","1.0.1-canary-f07d762-1654049397500":"2022-06-01T02:10:44.716Z","1.0.1-canary-f07d762-1654135408243":"2022-06-02T02:04:19.119Z","1.0.1-canary-f07d762-1654135427904":"2022-06-02T02:04:36.932Z","1.0.1-canary-f07d762-1654481051315":"2022-06-06T02:05:02.918Z","1.0.1-canary-f07d762-1654653730041":"2022-06-08T02:03:08.785Z","1.0.1-canary-f07d762-1655690661708":"2022-06-20T02:05:07.218Z","1.0.1-canary-f07d762-1655777284220":"2022-06-21T02:08:54.108Z","1.0.1-canary-f07d762-1656064386298":"2022-06-24T09:54:06.481Z","1.0.1-canary-f07d762-1656296141566":"2022-06-27T02:16:34.161Z","1.0.1-canary-f07d762-1656296250510":"2022-06-27T02:18:21.878Z","1.0.1-canary-f07d762-1656381846589":"2022-06-28T02:04:57.845Z","1.0.1-canary-f07d762-1656900179721":"2022-07-04T02:03:54.684Z","1.0.1-canary-f07d762-1656900277399":"2022-07-04T02:05:27.168Z","1.0.1-canary-f07d762-1657245815754":"2022-07-08T02:04:39.947Z","1.0.1-canary-f07d762-1657505351465":"2022-07-11T02:09:57.706Z","1.0.1-canary-f07d762-1657505493262":"2022-07-11T02:12:25.783Z","1.0.1-canary-f07d762-1658109887094":"2022-07-18T02:06:02.316Z","1.0.1-canary-f07d762-1658109901212":"2022-07-18T02:06:04.286Z","1.0.1-canary-f07d762-1658109934928":"2022-07-18T02:06:22.250Z","1.0.1-canary-f07d762-1658281516370":"2022-07-20T01:46:17.358Z","1.0.1-canary-f07d762-1658714680437":"2022-07-25T02:05:43.859Z","1.0.1-canary-f07d762-1658887361101":"2022-07-27T02:03:37.879Z","1.0.1-canary-f07d762-1658973717872":"2022-07-28T02:02:48.252Z","1.0.1-canary-f07d762-1659319954596":"2022-08-01T02:13:26.261Z","1.0.1-canary-f07d762-1659405782966":"2022-08-02T02:03:59.232Z","1.0.1-canary-f07d762-1659924257781":"2022-08-08T02:05:05.456Z","1.0.1-canary-f07d762-1660269737621":"2022-08-12T02:03:02.340Z","1.0.1-canary-f07d762-1660529100798":"2022-08-15T02:06:01.420Z","1.0.1-canary-f07d762-1660529139621":"2022-08-15T02:06:36.815Z","1.0.1-canary-f07d762-1661133896211":"2022-08-22T02:05:47.839Z","1.0.1-canary-f07d762-1661738862203":"2022-08-29T02:08:38.954Z","1.0.1-canary-f07d762-1661738960872":"2022-08-29T02:10:19.414Z","1.0.1-canary-f07d762-1661997888490":"2022-09-01T02:05:37.651Z","1.0.1-canary-f07d762-1661997907021":"2022-09-01T02:06:03.591Z","1.0.1-canary-f07d762-1662382366553":"2022-09-05T12:53:47.624Z","1.0.1-canary-f07d762-1663034663852":"2022-09-13T02:05:15.314Z","1.0.1-canary-f07d762-1663553270612":"2022-09-19T02:08:44.106Z","1.0.1-canary-f07d762-1663898620510":"2022-09-23T02:04:38.955Z","1.0.1-canary-f07d762-1664157959216":"2022-09-26T02:06:58.002Z","1.0.1-canary-f07d762-1665367698034":"2022-10-10T02:09:10.444Z","1.0.1-canary-f07d762-1665367877607":"2022-10-10T02:12:18.860Z","1.0.1-canary-f07d762-1665453779558":"2022-10-11T02:03:44.194Z","1.0.1-canary-f07d762-1666144978962":"2022-10-19T02:03:47.346Z","1.0.1-canary-f07d762-1666317907483":"2022-10-21T02:05:59.106Z","1.0.1-canary-f07d762-1666576903167":"2022-10-24T02:02:31.528Z","1.0.1-canary-f07d762-1666577031364":"2022-10-24T02:04:38.347Z","1.0.1-canary-f07d762-1666577075239":"2022-10-24T02:05:29.692Z","1.0.1-canary-f07d762-1667181742373":"2022-10-31T02:03:11.807Z","1.0.1-canary-f07d762-1667786536916":"2022-11-07T02:03:02.015Z","1.0.1-canary-f07d762-1667786647779":"2022-11-07T02:04:53.737Z","1.0.1-canary-f07d762-1668391468215":"2022-11-14T02:05:20.697Z","1.0.1-canary-f07d762-1668996225529":"2022-11-21T02:04:31.158Z","1.0.1-canary-f07d762-1669601139738":"2022-11-28T02:06:30.642Z","1.0.1-canary-f07d762-1670205972153":"2022-12-05T02:06:56.771Z","1.0.1-canary-f07d762-1670319096136":"2022-12-06T09:32:19.673Z","1.0.1-canary-f07d762-1670464891557":"2022-12-08T02:02:33.148Z","1.0.1-canary-f07d762-1670755820150":"2022-12-11T10:51:09.269Z","1.0.1-canary-f07d762-1670810566504":"2022-12-12T02:03:40.876Z","1.0.1-canary-f07d762-1671156059279":"2022-12-16T02:01:44.051Z","1.0.1-canary-f07d762-1671415306995":"2022-12-19T02:02:42.249Z","1.0.1-canary-f07d762-1671415353243":"2022-12-19T02:03:37.026Z","1.0.1-canary-f07d762-1671415397506":"2022-12-19T02:04:04.822Z","1.0.1-canary-f07d762-1672606645423":"2023-01-01T20:58:10.348Z","1.0.1-canary-f07d762-1672624951306":"2023-01-02T02:03:17.524Z","1.0.1-canary-f07d762-1673119159310":"2023-01-07T19:20:14.904Z","1.0.1-canary-f07d762-1673229859074":"2023-01-09T02:05:05.747Z","1.0.1-canary-f07d762-1673836041330":"2023-01-16T02:28:18.301Z","1.0.1-canary-f07d762-1674441891652":"2023-01-23T02:45:39.858Z","1.0.1-canary-f07d762-1675044780414":"2023-01-30T02:13:48.524Z","1.0.1-canary-f07d762-1676258231170":"2023-02-13T03:18:00.555Z","1.0.1-canary-f07d762-1676258327053":"2023-02-13T03:19:32.317Z","1.0.1-canary-f07d762-1677467426904":"2023-02-27T03:11:18.539Z","1.0.1-canary-f07d762-1677467447747":"2023-02-27T03:11:41.562Z","1.0.1-canary-f07d762-1677979873279":"2023-03-05T01:32:04.689Z"},"bugs":{"url":"https://github.com/iadvize/opaque-union-library/issues"},"author":{"name":"iAdvize developers"},"license":"MIT","homepage":"https://github.com/iadvize/opaque-union-library#readme","keywords":["iAdvize"],"repository":{"url":"git+https://github.com/iadvize/opaque-union-library.git","type":"git"},"description":"Functional opaque union api for Typescript and Javascript","maintainers":[{"email":"david.bonnemaison@iadvize.com","name":"davidiadvize"},{"email":"npm-iadvize-oss@iadvize.com","name":"iadvize-bot"},{"email":"jules.trehorel@iadvize.com","name":"jules.trehorel"},{"email":"simon.liotier@iadvize.com","name":"simon.liotier.iadvize"},{"email":"etienne.rouillard@iadvize.com","name":"etienne.rouillard.iadvize"},{"email":"ludovic.dupont29@gmail.com","name":"korial29"}],"readme":"","readmeFilename":""}